Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add example #2

Merged
merged 5 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Friendly Captcha Go Example

This application integrates Friendly Captcha for form submissions using Go.

### Requirements

- Go
- Your Friendly Captcha API key and site key.
rokostik marked this conversation as resolved.
Show resolved Hide resolved

### Start the application

- Setup env variables and start the application

> NOTE: `FRC_SITEVERIFY_ENDPOINT` and `FRC_WIDGET_ENDPOINT` are optional. If not set, the default values will be used. You can also use `global` or `eu` as shorthands for both.

```bash
FRC_APIKEY=<your api key> FRC_SITEKEY=<your site key> FRC_SITEVERIFY_ENDPINT=<siteverify endpoint> FRC_WIDGET_ENDPOINT=<widget endpoint> go run main.go
rokostik marked this conversation as resolved.
Show resolved Hide resolved
```

# Usage

Navigate to http://localhost:3000/ in your browser.
Fill out the form and submit. The Friendly Captcha verification will protect the form from bots.
83 changes: 83 additions & 0 deletions example/demo.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Friendly Captcha Python SDK example</title>
rokostik marked this conversation as resolved.
Show resolved Hide resolved
<style>
* {
box-sizing: border-box;
}

body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
width: 100vw;
background-color: #f2f2f2;
}

h1 {
font-size: 1.4em;
}

main {
width: 100%;
max-width: 680px;
}

.message {
width: 100%;
padding: 0.5em 2em;
margin: 1.5em 0;
border-radius: 8px;
}

.message h2 {
margin-bottom: 0;
}

label {
display: block;
}
</style>

<script type="module" src="https://cdn.jsdelivr.net/npm/@friendlycaptcha/sdk/site.min.js" async defer></script>
<script nomodule src="https://cdn.jsdelivr.net/npm/@friendlycaptcha/sdk/site.compat.min.js" async defer></script>

<!-- You can change the data-api-endpoint via this tag. More info here https://developer.friendlycaptcha.com/docs/sdk/configuration -->
<!-- <meta name="frc-api-endpoint" content="."> -->
</head>

<body>
<main>
<h1>Friendly Captcha Go SDK form</h1>
{{if .Message}}
<p>{{.Message}}</p>
{{end}}
<form method="POST">
<div class="form-group">
<label>Subject:</label><br />
<input type="text" name="subject" /><br />
<label>Message:</label><br />
<textarea name="message"></textarea><br />

<div class="frc-captcha" data-sitekey="{{.Sitekey}}" {{if
.WidgetEndpoint}}data-api-endpoint="{{.WidgetEndpoint}}" {{end}}></div>
<input style="margin-top: 1em" type="submit" value="Submit" />
</div>
</form>
</main>
<script>
if (window.history.replaceState) {
window.history.replaceState(null, null, window.location.href);
}
</script>
</body>

</html>
8 changes: 8 additions & 0 deletions example/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module github.com/friendlycaptcha/friendly-captcha-go/example

// TODO replace when module is published
replace github.com/friendlycaptcha/friendly-captcha-go => ../

go 1.21.6

require github.com/friendlycaptcha/friendly-captcha-go v0.0.0-00010101000000-000000000000
8 changes: 8 additions & 0 deletions example/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
109 changes: 109 additions & 0 deletions example/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package main

import (
"html/template"
"log"
"net/http"
"os"

friendlycaptcha "github.com/friendlycaptcha/friendly-captcha-go"
)

type formMessage struct {
Subject string
Message string
}

type templateData struct {
Message string
Sitekey string
WidgetEndpoint string
}

func main() {
sitekey := os.Getenv("FRC_SITEKEY")
apikey := os.Getenv("FRC_APIKEY")

// Optionally we can pass in custom endpoints to be used, such as "eu".
siteverifyEndpoint := os.Getenv("FRC_SITEVERIFY_ENDPOINT")
widgetEndpoint := os.Getenv("FRC_WIDGET_ENDPOINT")

if sitekey == "" || apikey == "" {
log.Fatalf("Please set the FRC_SITEKEY and FRC_APIKEY environment values before running this example to your Friendly Captcha sitekey and apikey respectively.")
rokostik marked this conversation as resolved.
Show resolved Hide resolved
}

opts := []friendlycaptcha.ClientOption{
friendlycaptcha.WithAPIKey(apikey),
friendlycaptcha.WithSitekey(sitekey),
}
if siteverifyEndpoint != "" {
opts = append(opts, friendlycaptcha.WithSiteverifyEndpoint(siteverifyEndpoint)) // optional, defaults to "global"
}
frcClient := friendlycaptcha.NewClient(opts...)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not so much a comment on this example, more on the SDK in general.

I think it may be worth considering returning an error as well here. Right now there is no part of the setup that can go wrong, but perhaps in the future we can add some sanity checks for the values entered - and it would be a breaking change if we wanted to change that.

What do you think?

Each of the Options could return an error.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a really good idea. Implemented in 3ff7bdc. Already looks better because we don't panic if user forgot to set API key.

tmpl := template.Must(template.ParseFiles("demo.html"))

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// GET - the user is requesting the form, not submitting it.
if r.Method != http.MethodPost {
err := tmpl.Execute(w, templateData{
Message: "",
Sitekey: sitekey,
WidgetEndpoint: widgetEndpoint,
})
if err != nil {
log.Fatal("erorr executing template: ", err)
rokostik marked this conversation as resolved.
Show resolved Hide resolved
}
return
}

form := formMessage{
Subject: r.FormValue("subject"),
Message: r.FormValue("message"),
}

solution := r.FormValue("frc-captcha-response")
result := frcClient.VerifyCaptchaResponse(r.Context(), solution)

if !result.WasAbleToVerify() {
// In this case we were not actually able to verify the response embedded in the form, but we may still want to accept it.
// It could mean there is a network issue or that the service is down. In those cases you generally want to accept submissions anyhow.
// That's why we use `shouldAccept()` below to actually accept or reject the form submission. It will return true in these cases.

if result.IsErrorDueToClientError() {
// Something is wrong with our configuration, check your API key!
// Send yourself an alert to fix this! Your site is unprotected until you fix this.
log.Printf("CAPTCHA CONFIG ERROR: %s\n", result.RequestError())
} else {
log.Printf("Failed to verify captcha response: %s\n", result.RequestError())
}
}

if !result.ShouldAccept() {
err := tmpl.Execute(w, templateData{
Message: "❌ Anti-robot check failed, please try again.",
Sitekey: sitekey,
WidgetEndpoint: widgetEndpoint,
})
if err != nil {
log.Fatal("erorr executing template: ", err)
rokostik marked this conversation as resolved.
Show resolved Hide resolved
}
return
}

// The captcha was OK, process the form.
_ = form
rokostik marked this conversation as resolved.
Show resolved Hide resolved

err := tmpl.Execute(w, templateData{
Message: "✅ Your message has been submitted successfully.",
Sitekey: sitekey,
WidgetEndpoint: widgetEndpoint,
})
if err != nil {
log.Fatal("erorr executing template: ", err)
rokostik marked this conversation as resolved.
Show resolved Hide resolved
}
})
log.Printf("Starting server on localhost port 8844 (http://localhost:8844)")
rokostik marked this conversation as resolved.
Show resolved Hide resolved

//nolint:errcheck,gosec // this is an example
rokostik marked this conversation as resolved.
Show resolved Hide resolved
http.ListenAndServe(":8844", nil)
}
Loading