49 lines
1.2 KiB
Go
49 lines
1.2 KiB
Go
|
package middleware
|
||
|
|
||
|
import (
|
||
|
"net/http"
|
||
|
"time"
|
||
|
|
||
|
"git.kirsle.net/apps/gophertype/pkg/constants"
|
||
|
"git.kirsle.net/apps/gophertype/pkg/responses"
|
||
|
uuid "github.com/satori/go.uuid"
|
||
|
)
|
||
|
|
||
|
// CSRF prevents Cross-Site Request Forgery.
|
||
|
// All "POST" requests are required to have an "_csrf" variable passed in which
|
||
|
// matches the "csrf_token" HTTP cookie with their request.
|
||
|
func CSRF(next http.Handler) http.Handler {
|
||
|
middleware := func(w http.ResponseWriter, r *http.Request) {
|
||
|
// All requests: verify they have a CSRF cookie, create one if not.
|
||
|
var token string
|
||
|
cookie, err := r.Cookie(constants.CSRFCookieName)
|
||
|
if err == nil {
|
||
|
token = cookie.Value
|
||
|
}
|
||
|
|
||
|
// Generate a token cookie if not found.
|
||
|
if len(token) < 8 || err != nil {
|
||
|
token = uuid.NewV4().String()
|
||
|
cookie = &http.Cookie{
|
||
|
Name: constants.CSRFCookieName,
|
||
|
Value: token,
|
||
|
Expires: time.Now().Add(24 * time.Hour),
|
||
|
}
|
||
|
http.SetCookie(w, cookie)
|
||
|
}
|
||
|
|
||
|
// POST requests: verify token from form parameter.
|
||
|
if r.Method == http.MethodPost {
|
||
|
compare := r.FormValue(constants.CSRFFormName)
|
||
|
if compare != token {
|
||
|
responses.Panic(w, http.StatusForbidden, "CSRF token failure.")
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
|
||
|
next.ServeHTTP(w, r)
|
||
|
}
|
||
|
|
||
|
return http.HandlerFunc(middleware)
|
||
|
}
|