github.com/gofiber/fiber/v2@v2.47.0/middleware/csrf/csrf.go (about)

     1  package csrf
     2  
     3  import (
     4  	"errors"
     5  	"time"
     6  
     7  	"github.com/gofiber/fiber/v2"
     8  )
     9  
    10  var errTokenNotFound = errors.New("csrf token not found")
    11  
    12  // New creates a new middleware handler
    13  func New(config ...Config) fiber.Handler {
    14  	// Set default config
    15  	cfg := configDefault(config...)
    16  
    17  	// Create manager to simplify storage operations ( see manager.go )
    18  	manager := newManager(cfg.Storage)
    19  
    20  	dummyValue := []byte{'+'}
    21  
    22  	// Return new handler
    23  	return func(c *fiber.Ctx) error {
    24  		// Don't execute middleware if Next returns true
    25  		if cfg.Next != nil && cfg.Next(c) {
    26  			return c.Next()
    27  		}
    28  
    29  		var token string
    30  
    31  		// Action depends on the HTTP method
    32  		switch c.Method() {
    33  		case fiber.MethodGet, fiber.MethodHead, fiber.MethodOptions, fiber.MethodTrace:
    34  			// Declare empty token and try to get existing CSRF from cookie
    35  			token = c.Cookies(cfg.CookieName)
    36  		default:
    37  			// Assume that anything not defined as 'safe' by RFC7231 needs protection
    38  
    39  			// Extract token from client request i.e. header, query, param, form or cookie
    40  			token, err := cfg.Extractor(c)
    41  			if err != nil {
    42  				return cfg.ErrorHandler(c, err)
    43  			}
    44  
    45  			// if token does not exist in Storage
    46  			if manager.getRaw(token) == nil {
    47  				// Expire cookie
    48  				c.Cookie(&fiber.Cookie{
    49  					Name:        cfg.CookieName,
    50  					Domain:      cfg.CookieDomain,
    51  					Path:        cfg.CookiePath,
    52  					Expires:     time.Now().Add(-1 * time.Minute),
    53  					Secure:      cfg.CookieSecure,
    54  					HTTPOnly:    cfg.CookieHTTPOnly,
    55  					SameSite:    cfg.CookieSameSite,
    56  					SessionOnly: cfg.CookieSessionOnly,
    57  				})
    58  				return cfg.ErrorHandler(c, errTokenNotFound)
    59  			}
    60  		}
    61  
    62  		// Generate CSRF token if not exist
    63  		if token == "" {
    64  			// And generate a new token
    65  			token = cfg.KeyGenerator()
    66  		}
    67  
    68  		// Add/update token to Storage
    69  		manager.setRaw(token, dummyValue, cfg.Expiration)
    70  
    71  		// Create cookie to pass token to client
    72  		cookie := &fiber.Cookie{
    73  			Name:        cfg.CookieName,
    74  			Value:       token,
    75  			Domain:      cfg.CookieDomain,
    76  			Path:        cfg.CookiePath,
    77  			Expires:     time.Now().Add(cfg.Expiration),
    78  			Secure:      cfg.CookieSecure,
    79  			HTTPOnly:    cfg.CookieHTTPOnly,
    80  			SameSite:    cfg.CookieSameSite,
    81  			SessionOnly: cfg.CookieSessionOnly,
    82  		}
    83  		// Set cookie to response
    84  		c.Cookie(cookie)
    85  
    86  		// Protect clients from caching the response by telling the browser
    87  		// a new header value is generated
    88  		c.Vary(fiber.HeaderCookie)
    89  
    90  		// Store token in context if set
    91  		if cfg.ContextKey != "" {
    92  			c.Locals(cfg.ContextKey, token)
    93  		}
    94  
    95  		// Continue stack
    96  		return c.Next()
    97  	}
    98  }