1
0
mirror of https://github.com/gofiber/fiber.git synced 2025-02-23 10:23:50 +00:00

99 lines
2.4 KiB
Go
Raw Normal View History

2020-09-13 11:20:11 +02:00
package csrf
import (
"errors"
2020-09-13 11:20:11 +02:00
"time"
"github.com/gofiber/fiber/v2"
)
var (
errTokenNotFound = errors.New("csrf token not found")
)
2020-09-13 11:20:11 +02:00
// New creates a new middleware handler
func New(config ...Config) fiber.Handler {
// Set default config
2021-03-09 09:29:47 -05:00
cfg := configDefault(config...)
2020-09-13 11:20:11 +02:00
2020-11-23 07:38:42 +01:00
// Create manager to simplify storage operations ( see manager.go )
manager := newManager(cfg.Storage)
2020-09-13 11:20:11 +02:00
2020-11-23 07:38:42 +01:00
dummyValue := []byte{'+'}
2020-09-13 11:20:11 +02:00
// Return new handler
2020-11-11 21:44:37 +01:00
return func(c *fiber.Ctx) (err error) {
2020-09-13 11:20:11 +02:00
// Don't execute middleware if Next returns true
2020-11-11 15:25:35 +01:00
if cfg.Next != nil && cfg.Next(c) {
2020-09-13 11:20:11 +02:00
return c.Next()
}
2020-11-11 21:44:37 +01:00
var token string
2020-11-11 15:25:35 +01:00
// Action depends on the HTTP method
switch c.Method() {
case fiber.MethodGet, fiber.MethodHead, fiber.MethodOptions, fiber.MethodTrace:
2020-11-11 15:25:35 +01:00
// Declare empty token and try to get existing CSRF from cookie
2020-11-14 03:09:53 +01:00
token = c.Cookies(cfg.CookieName)
default:
// Assume that anything not defined as 'safe' by RFC7231 needs protection
2020-11-11 15:25:35 +01:00
// Extract token from client request i.e. header, query, param, form or cookie
2021-03-01 16:25:32 -05:00
token, err = cfg.extractor(c)
2020-09-13 11:20:11 +02:00
if err != nil {
return cfg.ErrorHandler(c, err)
2020-09-13 11:20:11 +02:00
}
2020-11-23 07:38:42 +01:00
// if token does not exist in Storage
2020-11-23 07:38:42 +01:00
if manager.getRaw(token) == nil {
2020-11-11 15:25:35 +01:00
// Expire cookie
c.Cookie(&fiber.Cookie{
2020-11-14 03:09:53 +01:00
Name: cfg.CookieName,
Domain: cfg.CookieDomain,
Path: cfg.CookiePath,
2020-11-11 15:25:35 +01:00
Expires: time.Now().Add(-1 * time.Minute),
2020-11-14 03:09:53 +01:00
Secure: cfg.CookieSecure,
HTTPOnly: cfg.CookieHTTPOnly,
SameSite: cfg.CookieSameSite,
2020-11-11 15:25:35 +01:00
})
return cfg.ErrorHandler(c, errTokenNotFound)
2020-09-13 11:20:11 +02:00
}
}
// Generate CSRF token if not exist
if token == "" {
// And generate a new token
token = cfg.KeyGenerator()
}
2020-11-23 07:38:42 +01:00
// Add/update token to Storage
manager.setRaw(token, dummyValue, cfg.Expiration)
// Create cookie to pass token to client
cookie := &fiber.Cookie{
Name: cfg.CookieName,
Value: token,
Domain: cfg.CookieDomain,
Path: cfg.CookiePath,
Expires: time.Now().Add(cfg.Expiration),
Secure: cfg.CookieSecure,
HTTPOnly: cfg.CookieHTTPOnly,
SameSite: cfg.CookieSameSite,
2020-09-13 11:20:11 +02:00
}
// Set cookie to response
c.Cookie(cookie)
2020-09-13 11:20:11 +02:00
2020-11-11 21:44:37 +01:00
// Protect clients from caching the response by telling the browser
// a new header value is generated
c.Vary(fiber.HeaderCookie)
// Store token in context if set
if cfg.ContextKey != "" {
c.Locals(cfg.ContextKey, token)
}
2020-09-13 11:20:11 +02:00
// Continue stack
return c.Next()
}
}