middleware

package
v0.0.0-...-1ef12ea Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 13, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrExtractorError = wo.ErrForbidden.WithMessage("error while extracting identifier")

ErrExtractorError denotes an error raised when extractor function is unsuccessful

View Source
var ErrRateLimitExceeded = wo.ErrTooManyRequests.WithMessage("rate limit exceeded")

ErrRateLimitExceeded denotes an error raised when rate limit is exceeded

Functions

func BodyLimit

func BodyLimit[T wo.Resolver](cfg BodyLimitConfig, skippers ...Skipper[T]) func(T) error

func BodyRereadable

func BodyRereadable[T wo.Resolver](skippers ...Skipper[T]) func(T) error

func CORS

func CORS[T wo.Resolver](cfg CORSConfig, skippers ...Skipper[T]) func(T) error

func CheckMethod

func CheckMethod(method, skip string) (string, bool)

func Compress

func Compress[T wo.Resolver](cfg CompressConfig, skippers ...Skipper[T]) func(T) error

func RateLimiter

func RateLimiter[T wo.Resolver](cfg RateLimiterConfig[T], skippers ...Skipper[T]) func(T) error

RateLimiter middleware implements the sliding-window rate limiting strategy

func Recover

func Recover[T wo.Resolver](cfg RecoverConfig) func(T) error

func RequestLogger

func RequestLogger[T wo.Resolver](logger *slog.Logger, attrFunc func(e T, status int, err error) []slog.Attr, skippers ...Skipper[T]) func(T) error

func Security

func Security[T wo.Resolver](cfg SecurityConfig, skippers ...Skipper[T]) func(T) error

func Session

func Session[T wo.Resolver](s *session.Session, logger ErrorLogger, skippers ...Skipper[T]) func(T) error

Types

type BodyLimitConfig

type BodyLimitConfig struct {
	// Maximum allowed size for a request body, default is 32MB.
	// If Limit is less to 0, no limit is applied.
	Limit int64 `env:"LIMIT" json:"limit,omitempty" yaml:"limit,omitempty"`
}

func (*BodyLimitConfig) SetDefaults

func (c *BodyLimitConfig) SetDefaults()

type CORSConfig

type CORSConfig struct {
	// AllowOrigins determines the value of the Access-Control-Allow-Origin
	// response header.  This header defines a list of origins that may access the
	// resource.  The wildcard characters '*' and '?' are supported and are
	// converted to regex fragments '.*' and '.' accordingly.
	//
	// Security: use extreme caution when handling the origin, and carefully
	// validate any logic. Remember that attackers may register hostile domain names.
	// See https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html
	//
	// Optional. Default value []string{"*"}.
	//
	// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
	AllowOrigins []string `env:"ALLOW_ORIGINS" json:"allowOrigins,omitempty" yaml:"allowOrigins,omitempty"`

	// AllowOriginFunc is a custom function to validate the origin. It takes the
	// origin as an argument and returns true if allowed or false otherwise. If
	// an error is returned, it is returned by the handler. If this option is
	// set, AllowOrigins is ignored.
	//
	// Security: use extreme caution when handling the origin, and carefully
	// validate any logic. Remember that attackers may register hostile domain names.
	// See https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html
	//
	// Optional.
	AllowOriginFunc func(origin string) (bool, error) `json:"-" yaml:"-"`

	// AllowMethods determines the value of the Access-Control-Allow-Methods
	// response header.  This header specified the list of methods allowed when
	// accessing the resource.  This is used in response to a preflight request.
	//
	// Optional. Default value DefaultCORSConfig.AllowMethods.
	// If `allowMethods` is left empty, this middleware will fill for preflight
	// request `Access-Control-Allow-Methods` header value
	// from `Allow` header that echo.Router set into context.
	//
	// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods
	AllowMethods []string `env:"ALLOW_METHODS" json:"allowMethods,omitempty" yaml:"allowMethods,omitempty"`

	// AllowHeaders determines the value of the Access-Control-Allow-Headers
	// response header.  This header is used in response to a preflight request to
	// indicate which HTTP headers can be used when making the actual request.
	//
	// Optional. Default value []string{}.
	//
	// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
	AllowHeaders []string `env:"ALLOW_HEADERS" json:"allowHeaders,omitempty" yaml:"allowHeaders,omitempty"`

	// AllowCredentials determines the value of the
	// Access-Control-Allow-Credentials response header.  This header indicates
	// whether or not the response to the request can be exposed when the
	// credentials mode (Request.credentials) is true. When used as part of a
	// response to a preflight request, this indicates whether or not the actual
	// request can be made using credentials.  See also
	// [MDN: Access-Control-Allow-Credentials].
	//
	// Optional. Default value false, in which case the header is not set.
	//
	// Security: avoid using `AllowCredentials = true` with `AllowOrigins = *`.
	// See "Exploiting CORS misconfigurations for Bitcoins and bounties",
	// https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html
	//
	// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials
	AllowCredentials bool `env:"ALLOW_CREDENTIALS" json:"allowCredentials,omitempty" yaml:"allowCredentials,omitempty"`

	// UnsafeWildcardOriginWithAllowCredentials UNSAFE/INSECURE: allows wildcard '*' origin to be used with AllowCredentials
	// flag. In that case we consider any origin allowed and send it back to the client with `Access-Control-Allow-Origin` header.
	//
	// This is INSECURE and potentially leads to [cross-origin](https://portswigger.net/research/exploiting-cors-misconfigurations-for-bitcoins-and-bounties)
	// attacks. See: https://github.com/labstack/echo/issues/2400 for discussion on the subject.
	//
	// Optional. Default value is false.
	UnsafeWildcardOriginWithAllowCredentials bool `` /* 167-byte string literal not displayed */

	// ExposeHeaders determines the value of Access-Control-Expose-Headers, which
	// defines a list of headers that clients are allowed to access.
	//
	// Optional. Default value []string{}, in which case the header is not set.
	//
	// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Header
	ExposeHeaders []string `env:"EXPOSE_HEADERS" json:"exposeHeaders,omitempty" yaml:"exposeHeaders,omitempty"`

	// MaxAge determines the value of the Access-Control-Max-Age response header.
	// This header indicates how long (in seconds) the results of a preflight
	// request can be cached.
	// The header is set only if MaxAge != 0, negative value sends "0" which instructs browsers not to cache that response.
	//
	// Optional. Default value 0 - meaning header is not sent.
	//
	// See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age
	MaxAge int `env:"MAX_AGE" json:"maxAge,omitempty" yaml:"maxAge,omitempty"`
}

func (*CORSConfig) SetDefaults

func (c *CORSConfig) SetDefaults()

type CompressConfig

type CompressConfig struct {
	// Gzip compression level.
	// Optional. Default value -1.
	Level int `env:"LEVEL" json:"level,omitempty" yaml:"level,omitempty"`

	// Length threshold before gzip compression is applied.
	// Optional. Default value 1024.
	//
	// Most of the time you will not need to change the default. Compressing
	// a short response might increase the transmitted data because of the
	// gzip format overhead. Compressing the response will also consume CPU
	// and time on the server and the client (for decompressing). Depending on
	// your use case such a threshold might be useful.
	//
	// See also:
	// https://webmasters.stackexchange.com/questions/31750/what-is-recommended-minimum-object-size-for-gzip-performance-benefits
	MinLength int `env:"MIN_LENGTH" json:"minLength,omitempty" yaml:"minLength,omitempty"`
}

func (*CompressConfig) SetDefaults

func (c *CompressConfig) SetDefaults()

func (*CompressConfig) Validate

func (c *CompressConfig) Validate() error

type ErrorLogger

type ErrorLogger interface {
	Error(msg string, keysAndValues ...any)
}

type RateLimiterConfig

type RateLimiterConfig[T wo.Resolver] struct {
	// Storage is used to store the state of the middleware
	//
	// Default: in memory storage
	Storage RateLimiterStorage `json:"-" yaml:"-"`

	// TimestampFunc return current unix timestamp (seconds)
	// max value is 4294967295 -> Sun Feb 07 2106 06:28:15 GMT+0000
	//
	// Default: func() uint32 {
	//   return uint32(time.Now().Unix())
	// }
	TimestampFunc func() uint32 `json:"-" yaml:"-"`

	// IdentifierExtractor uses T wo.Resolver to extract the identifier, by default c.Request().RemoteAddr is used
	//
	// Default: func(c T) string {
	//   return c.Request().RemoteAddr
	// }
	IdentifierExtractor func(T) (string, error) `json:"-" yaml:"-"`

	// Max number of recent connections during `Expiration` seconds before sending a 429 response
	//
	// Default: 5
	Max uint `env:"MAX" json:"max,omitempty" yaml:"max,omitempty"`

	// MaxFunc a function to dynamically calculate the max requests supported by the rate limiter middleware
	//
	// Default: func(T) int {
	//   return c.Max
	// }
	MaxFunc func(T) uint `json:"-" yaml:"-"`

	// Expiration is the time on how long to keep records of requests in memory
	//
	// Default: 1 * time.Minute
	Expiration time.Duration `env:"EXPIRATION" json:"expiration,omitempty,format:units" yaml:"expiration,omitempty"`

	// ExpirationFunc a function to dynamically calculate the expiration supported by the rate limiter middleware
	//
	// Default: func(T) time.Duration {
	//   return c.Expiration
	// }
	ExpirationFunc func(T) time.Duration `json:"-" yaml:"-"`

	// When set to true, the middleware will not include the rate limit headers (X-RateLimit-* and Retry-After) in the response.
	//
	// Default: false
	DisableHeaders bool `env:"DISABLE_HEADERS" json:"disableHeaders,omitempty" yaml:"disableHeaders,omitempty"`

	// DisableValueRedaction turns off masking limiter keys in logs and error messages when set to true.
	//
	// Default: false
	DisableValueRedaction bool `env:"DISABLE_VALUE_REDACTION" json:"disableValueRedaction,omitempty" yaml:"disableValueRedaction,omitempty"`
}

func (*RateLimiterConfig[T]) SetDefaults

func (c *RateLimiterConfig[T]) SetDefaults()

type RateLimiterMemoryStorage

type RateLimiterMemoryStorage struct {
	// contains filtered or unexported fields
}

func NewRateLimiterMemoryStorage

func NewRateLimiterMemoryStorage(timestampFunc func() uint32) *RateLimiterMemoryStorage

func (*RateLimiterMemoryStorage) Get

Get retrieves the value stored under key, returning nil when the entry does not exist or has expired.

For []byte values, this returns a defensive copy to prevent callers from mutating the stored data. Other types are returned as-is.

func (*RateLimiterMemoryStorage) Set

Set stores val under key and applies the optional ttl before expiring the entry. A non-positive ttl keeps the item forever.

String keys are defensively copied to prevent corruption from pooled buffers. []byte values are also copied to prevent external mutation of stored data. Other types are stored as-is (structs are copied by value automatically).

type RateLimiterStorage

type RateLimiterStorage interface {
	// Get gets the value for the given key with a context.
	// `nil, nil` is returned when the key does not exist
	Get(ctx context.Context, key string) ([]byte, error)

	// Set stores the given value for the given key with an expiration value.
	Set(ctx context.Context, key string, value []byte, exp time.Duration) error
}

type RecoverConfig

type RecoverConfig struct {
	// Size of the stack to be printed.
	// Optional. Default value 2KB.
	StackSize int `env:"STACK_SIZE" json:"stackSize,omitempty" yaml:"stackSize,omitempty"`
}

func (*RecoverConfig) SetDefaults

func (c *RecoverConfig) SetDefaults()

type SecurityConfig

type SecurityConfig struct {
	// XSSProtection provides protection against cross-site scripting attack (XSS)
	// by setting the `X-XSS-Protection` header.
	// Optional. Default value "1; mode=block".
	XSSProtection string `env:"XSS_PROTECTION" json:"xssProtection,omitempty" yaml:"xssProtection,omitempty"`

	// ContentTypeNosniff provides protection against overriding Content-Type
	// header by setting the `X-Content-Type-Options` header.
	// Optional. Default value "nosniff".
	ContentTypeNosniff string `env:"CONTENT_TYPE_NO_SNIFF" json:"contentTypeNoSniff,omitempty" yaml:"contentTypeNoSniff,omitempty"`

	// XFrameOptions can be used to indicate whether or not a browser should
	// be allowed to render a page in a <frame>, <iframe> or <object> .
	// Sites can use this to avoid clickjacking attacks, by ensuring that their
	// content is not embedded into other sites.provides protection against
	// clickjacking.
	// Optional. Default value "SAMEORIGIN".
	// Possible values:
	// - "SAMEORIGIN" - The page can only be displayed in a frame on the same origin as the page itself.
	// - "DENY" - The page cannot be displayed in a frame, regardless of the site attempting to do so.
	// - "ALLOW-FROM uri" - The page can only be displayed in a frame on the specified origin.
	XFrameOptions string `env:"X_FRAME_OPTIONS" json:"xFrameOptions,omitempty" yaml:"xFrameOptions,omitempty"`

	// HSTSMaxAge sets the `Strict-Transport-Security` header to indicate how
	// long (in seconds) browsers should remember that this site is only to
	// be accessed using HTTPS. This reduces your exposure to some SSL-stripping
	// man-in-the-middle (MITM) attacks.
	// Optional. Default value 15724800.
	HSTSMaxAge int `env:"HSTS_MAX_AGE" json:"hstsMaxAge,omitempty" yaml:"hstsMaxAge,omitempty"`

	// HSTSExcludeSubdomains won't include subdomains tag in the `Strict Transport Security`
	// header, excluding all subdomains from security policy. It has no effect
	// unless HSTSMaxAge is set to a non-zero value.
	// Optional. Default value false.
	HSTSExcludeSubdomains bool `env:"HSTS_EXCLUDE_SUBDOMAINS" json:"hstsExcludeSubdomains,omitempty" yaml:"hstsExcludeSubdomains,omitempty"`

	// ContentSecurityPolicy sets the `Content-Security-Policy` header providing
	// security against cross-site scripting (XSS), clickjacking and other code
	// injection attacks resulting from execution of malicious content in the
	// trusted web page context.
	// Optional. Default value "".
	ContentSecurityPolicy string `env:"CONTENT_SECURITY_POLICY" json:"contentSecurityPolicy,omitempty" yaml:"contentSecurityPolicy,omitempty"`

	// CSPReportOnly would use the `Content-Security-Policy-Report-Only` header instead
	// of the `Content-Security-Policy` header. This allows iterative updates of the
	// content security policy by only reporting the violations that would
	// have occurred instead of blocking the resource.
	// Optional. Default value false.
	CSPReportOnly bool `env:"CSP_REPORT_ONLY" json:"cspReportOnly,omitempty" yaml:"cspReportOnly,omitempty"`

	// HSTSPreloadEnabled will add the preload tag in the `Strict Transport Security`
	// header, which enables the domain to be included in the HSTS preload list
	// maintained by Chrome (and used by Firefox and Safari): https://hstspreload.org/
	// Optional.  Default value false.
	HSTSPreloadEnabled bool `env:"HSTS_PRELOAD_ENABLED" json:"hstsPreloadEnabled,omitempty" yaml:"hstsPreloadEnabled,omitempty"`

	// ReferrerPolicy sets the `Referrer-Policy` header providing security against
	// leaking potentially sensitive request paths to third parties.
	// Optional. Default value "".
	ReferrerPolicy string `env:"REFERRER_POLICY" json:"referrerPolicy,omitempty" yaml:"referrerPolicy,omitempty"`
}

func (*SecurityConfig) SetDefaults

func (c *SecurityConfig) SetDefaults()

type Skipper

type Skipper[T wo.Resolver] func(e T) bool

func ChainSkipper

func ChainSkipper[T wo.Resolver](skippers ...Skipper[T]) Skipper[T]

func EqualPathSkipper

func EqualPathSkipper[T wo.Resolver](paths ...string) Skipper[T]

func PrefixPathSkipper

func PrefixPathSkipper[T wo.Resolver](prefixes ...string) Skipper[T]

func SuffixPathSkipper

func SuffixPathSkipper[T wo.Resolver](suffixes ...string) Skipper[T]

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL