From af9986c0f88660328885749240eeb393f926d533 Mon Sep 17 00:00:00 2001 From: "Jonathan Leibiusky @xetorthio" Date: Tue, 15 Nov 2016 16:53:44 -0300 Subject: [PATCH] Validates that user is a human. Add google recaptcha as an initial page before creating any session. To configure recaptcha there are 2 environment variables that are needed `GOOGLE_RECAPTCHA_SITE_KEY` and `GOOGLE_RECAPTCHA_SITE_SECRET`. The code contains development defaults that should be set in production to real values. **NOTICE: Development defaults assume that the domain is `localhost`** --- api.go | 12 +++++++- handlers/new_session.go | 7 +++++ services/recaptcha.go | 59 ++++++++++++++++++++++++++++++++++++++++ templates/welcome.go | 21 ++++++++++++++ www/assets/large_h.png | Bin 0 -> 35802 bytes www/assets/style.css | 15 ++++++++++ www/welcome.html | 27 ++++++++++++++++++ 7 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 services/recaptcha.go create mode 100644 templates/welcome.go create mode 100644 www/assets/large_h.png create mode 100644 www/welcome.html diff --git a/api.go b/api.go index fc652d7..9a909fc 100644 --- a/api.go +++ b/api.go @@ -7,12 +7,18 @@ import ( "github.com/franela/play-with-docker/handlers" "github.com/franela/play-with-docker/services" + "github.com/franela/play-with-docker/templates" "github.com/gorilla/mux" "github.com/urfave/negroni" ) func main() { + welcome, tmplErr := templates.GetWelcomeTemplate() + if tmplErr != nil { + log.Fatal(tmplErr) + } + server := services.CreateWSServer() server.On("connection", handlers.WS) @@ -27,7 +33,11 @@ func main() { r.StrictSlash(false) r.HandleFunc("/ping", http.HandlerFunc(handlers.Ping)).Methods("GET") - r.HandleFunc("/", http.HandlerFunc(handlers.NewSession)).Methods("GET") + r.HandleFunc("/", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + rw.Write(welcome) + })).Methods("GET") + r.HandleFunc("/", http.HandlerFunc(handlers.NewSession)).Methods("POST") + r.HandleFunc("/sessions/{sessionId}", http.HandlerFunc(handlers.GetSession)).Methods("GET") r.HandleFunc("/sessions/{sessionId}/instances", http.HandlerFunc(handlers.NewInstance)).Methods("POST") r.HandleFunc("/sessions/{sessionId}/instances/{instanceName}", http.HandlerFunc(handlers.DeleteInstance)).Methods("DELETE") diff --git a/handlers/new_session.go b/handlers/new_session.go index d476f6a..8cb497c 100644 --- a/handlers/new_session.go +++ b/handlers/new_session.go @@ -9,6 +9,13 @@ import ( ) func NewSession(rw http.ResponseWriter, req *http.Request) { + if !services.IsHuman(req) { + // User it not a human + rw.WriteHeader(http.StatusConflict) + rw.Write([]byte("Only humans are allowed!")) + return + } + s, err := services.NewSession() if err != nil { log.Println(err) diff --git a/services/recaptcha.go b/services/recaptcha.go new file mode 100644 index 0000000..b3eb150 --- /dev/null +++ b/services/recaptcha.go @@ -0,0 +1,59 @@ +package services + +import ( + "encoding/json" + "log" + "net/http" + "net/url" + "os" + "strings" +) + +func GetGoogleRecaptchaSiteKey() string { + key := os.Getenv("GOOGLE_RECAPTCHA_SITE_KEY") + if key == "" { + // This is a development default. The environment variable should always be set in production. + key = "6LeY_QsUAAAAAOlpVw4MhoLEr50h-dM80oz6M2AX" + } + return key +} +func GetGoogleRecaptchaSiteSecret() string { + key := os.Getenv("GOOGLE_RECAPTCHA_SITE_SECRET") + if key == "" { + // This is a development default. The environment variable should always be set in production. + key = "6LeY_QsUAAAAAHIALCtm0GKfk-UhtXoyJKarnRV8" + } + + return key +} + +type recaptchaResponse struct { + Success bool `json:"success"` +} + +func IsHuman(req *http.Request) bool { + req.ParseForm() + challenge := req.Form.Get("g-recaptcha-response") + + // Of X-Forwarded-For exists, it means we are behind a loadbalancer and we should use the real IP address of the user + ip := req.Header.Get("X-Forwarded-For") + if ip == "" { + // Use the standard remote IP address of the request + + ip = req.RemoteAddr + } + + parts := strings.Split(ip, ":") + + resp, postErr := http.PostForm("https://www.google.com/recaptcha/api/siteverify", url.Values{"secret": {GetGoogleRecaptchaSiteSecret()}, "response": {challenge}, "remoteip": {parts[0]}}) + if postErr != nil { + log.Println(postErr) + // If there is a problem to connect to google, assume the user is a human so we don't block real users because of technical issues + return true + } + + var r recaptchaResponse + json.NewDecoder(resp.Body).Decode(&r) + + return r.Success +} diff --git a/templates/welcome.go b/templates/welcome.go new file mode 100644 index 0000000..d8eed5a --- /dev/null +++ b/templates/welcome.go @@ -0,0 +1,21 @@ +package templates + +import ( + "bytes" + "html/template" + + "github.com/franela/play-with-docker/services" +) + +func GetWelcomeTemplate() ([]byte, error) { + welcomeTemplate, tplErr := template.New("welcome").ParseFiles("www/welcome.html") + if tplErr != nil { + return nil, tplErr + } + var b bytes.Buffer + tplExecuteErr := welcomeTemplate.ExecuteTemplate(&b, "GOOGLE_RECAPTCHA_SITE_KEY", services.GetGoogleRecaptchaSiteKey()) + if tplExecuteErr != nil { + return nil, tplExecuteErr + } + return b.Bytes(), nil +} diff --git a/www/assets/large_h.png b/www/assets/large_h.png new file mode 100644 index 0000000000000000000000000000000000000000..eddd2b6cc2b026fa9d8a4c8b3ad6faa03837b56a GIT binary patch literal 35802 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 aMJ^iq6+0e!@0B&`pr2~!KQ33Zjrf0w>NU>* literal 0 HcmV?d00001 diff --git a/www/assets/style.css b/www/assets/style.css index d98c539..388c256 100644 --- a/www/assets/style.css +++ b/www/assets/style.css @@ -27,3 +27,18 @@ md-card-content.terminal { color: #1da4eb; text-align: center; } + +.welcome { + background-color: #e7e7e7; +} + +.welcome > div { + text-align: center; +} + +.g-recaptcha div { + margin-left: auto; + margin-right: auto; + margin-bottom: auto; + margin-top: 50px; +} diff --git a/www/welcome.html b/www/welcome.html new file mode 100644 index 0000000..512d7a1 --- /dev/null +++ b/www/welcome.html @@ -0,0 +1,27 @@ +{{define "GOOGLE_RECAPTCHA_SITE_KEY"}} + + + + Docker Playground + + + + + +
+

Welcome!

+

Before starting we need to verify you are a human

+
+
+
+ +
+ + + + +{{end}}