3ec367a759
* Added new dep: gorilla/csrf * CSRF field in forms * CSRF variable in commontemplatevariables * New key for messages and user context Please change EnableSecureCSRF to false when testing locally and don't merge config/env.go with the changes
82 lignes
2,1 Kio
Go
82 lignes
2,1 Kio
Go
package csrf
|
|
|
|
import (
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/gorilla/securecookie"
|
|
)
|
|
|
|
// store represents the session storage used for CSRF tokens.
|
|
type store interface {
|
|
// Get returns the real CSRF token from the store.
|
|
Get(*http.Request) ([]byte, error)
|
|
// Save stores the real CSRF token in the store and writes a
|
|
// cookie to the http.ResponseWriter.
|
|
// For non-cookie stores, the cookie should contain a unique (256 bit) ID
|
|
// or key that references the token in the backend store.
|
|
// csrf.GenerateRandomBytes is a helper function for generating secure IDs.
|
|
Save(token []byte, w http.ResponseWriter) error
|
|
}
|
|
|
|
// cookieStore is a signed cookie session store for CSRF tokens.
|
|
type cookieStore struct {
|
|
name string
|
|
maxAge int
|
|
secure bool
|
|
httpOnly bool
|
|
path string
|
|
domain string
|
|
sc *securecookie.SecureCookie
|
|
}
|
|
|
|
// Get retrieves a CSRF token from the session cookie. It returns an empty token
|
|
// if decoding fails (e.g. HMAC validation fails or the named cookie doesn't exist).
|
|
func (cs *cookieStore) Get(r *http.Request) ([]byte, error) {
|
|
// Retrieve the cookie from the request
|
|
cookie, err := r.Cookie(cs.name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
token := make([]byte, tokenLength)
|
|
// Decode the HMAC authenticated cookie.
|
|
err = cs.sc.Decode(cs.name, cookie.Value, &token)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return token, nil
|
|
}
|
|
|
|
// Save stores the CSRF token in the session cookie.
|
|
func (cs *cookieStore) Save(token []byte, w http.ResponseWriter) error {
|
|
// Generate an encoded cookie value with the CSRF token.
|
|
encoded, err := cs.sc.Encode(cs.name, token)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
cookie := &http.Cookie{
|
|
Name: cs.name,
|
|
Value: encoded,
|
|
MaxAge: cs.maxAge,
|
|
HttpOnly: cs.httpOnly,
|
|
Secure: cs.secure,
|
|
Path: cs.path,
|
|
Domain: cs.domain,
|
|
}
|
|
|
|
// Set the Expires field on the cookie based on the MaxAge
|
|
// If MaxAge <= 0, we don't set the Expires attribute, making the cookie
|
|
// session-only.
|
|
if cs.maxAge > 0 {
|
|
cookie.Expires = time.Now().Add(
|
|
time.Duration(cs.maxAge) * time.Second)
|
|
}
|
|
|
|
// Write the authenticated cookie to the response.
|
|
http.SetCookie(w, cookie)
|
|
|
|
return nil
|
|
}
|