diff --git a/example/README.md b/example/README.md new file mode 100644 index 0000000..ce74fb4 --- /dev/null +++ b/example/README.md @@ -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. + +### 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= FRC_SITEKEY= FRC_SITEVERIFY_ENDPINT= FRC_WIDGET_ENDPOINT= go run main.go +``` + +# 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. diff --git a/example/demo.html b/example/demo.html new file mode 100644 index 0000000..2b1a0b2 --- /dev/null +++ b/example/demo.html @@ -0,0 +1,83 @@ + + + + + + + + Friendly Captcha Python SDK example + + + + + + + + + + +
+

Friendly Captcha Go SDK form

+ {{if .Message}} +

{{.Message}}

+ {{end}} +
+
+
+
+
+
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/example/go.mod b/example/go.mod new file mode 100644 index 0000000..9e3176a --- /dev/null +++ b/example/go.mod @@ -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 diff --git a/example/go.sum b/example/go.sum new file mode 100644 index 0000000..8952aa2 --- /dev/null +++ b/example/go.sum @@ -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= diff --git a/example/main.go b/example/main.go new file mode 100644 index 0000000..0c60603 --- /dev/null +++ b/example/main.go @@ -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.") + } + + 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...) + 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) + } + 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) + } + return + } + + // The captcha was OK, process the form. + _ = form + + 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) + } + }) + log.Printf("Starting server on localhost port 8844 (http://localhost:8844)") + + //nolint:errcheck,gosec // this is an example + http.ListenAndServe(":8844", nil) +}