mirror of
https://github.com/bingohuang/docker-labs.git
synced 2025-07-15 02:37:27 +08:00
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`**
This commit is contained in:
parent
770945ab86
commit
af9986c0f8
12
api.go
12
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")
|
||||
|
@ -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)
|
||||
|
59
services/recaptcha.go
Normal file
59
services/recaptcha.go
Normal file
@ -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
|
||||
}
|
21
templates/welcome.go
Normal file
21
templates/welcome.go
Normal file
@ -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
|
||||
}
|
BIN
www/assets/large_h.png
Normal file
BIN
www/assets/large_h.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 35 KiB |
@ -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;
|
||||
}
|
||||
|
27
www/welcome.html
Normal file
27
www/welcome.html
Normal file
@ -0,0 +1,27 @@
|
||||
{{define "GOOGLE_RECAPTCHA_SITE_KEY"}}
|
||||
<!doctype html>
|
||||
<html ng-app="DockerPlay" ng-controller="PlayController">
|
||||
<head>
|
||||
<title>Docker Playground</title>
|
||||
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/angular_material/1.1.0/angular-material.min.css">
|
||||
<link rel="stylesheet" href="/assets/style.css" />
|
||||
<script src='https://www.google.com/recaptcha/api.js'></script>
|
||||
</head>
|
||||
<body class="welcome">
|
||||
<div>
|
||||
<h1>Welcome!</h1>
|
||||
<h2>Before starting we need to verify you are a human</h2>
|
||||
<form id="welcomeForm" method="POST" action="/">
|
||||
<div class="g-recaptcha" data-callback="iAmHuman" data-sitekey="{{.}}"></div>
|
||||
</form>
|
||||
<img src="/assets/large_h.png" />
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function iAmHuman(resp) {
|
||||
document.getElementById('welcomeForm').submit();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
Loading…
x
Reference in New Issue
Block a user