ratelimit

package
v0.5.2 Latest Latest
Warning

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

Go to latest
Published: May 18, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package ratelimit provides a small token-bucket rate-limit middleware used to protect anonymous attack surfaces (login, enroll) from brute-force / password-spray.

The Limiter is keyed by a caller-supplied function (IP, IP+username, etc.) so the same primitive can fan out to per-endpoint policies.

Index

Constants

View Source
const DefaultMaxBuckets = 100_000

DefaultMaxBuckets is the cap on the per-key map size. Once exceeded, new keys all share a single overflow bucket, so an attacker churning arbitrary keys (X-Forwarded-For spoofing or a similar primitive in a future surface) cannot grow the limiter's memory footprint unbounded.

Variables

This section is empty.

Functions

func KeyByIP

func KeyByIP(r *http.Request) string

KeyByIP is a convenience keyFn for IP-based rate limiting. Honors X-Real-IP / X-Forwarded-For via utils.GetIP.

Types

type Limiter

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

Limiter is a sharded map of token buckets keyed by an arbitrary string. Buckets age out after `evictAfter` of inactivity so the map doesn't grow unbounded. Eviction is amortized — the full O(N) scan runs at most once per `evictAfter/2` so a single hot-path Allow doesn't pay the cost. When the map exceeds maxBuckets, new keys collapse onto a shared overflow bucket; the spray still gets rate-limited (just not per-key) and memory stays bounded.

func New

func New(burst int, per, evictAfter time.Duration) *Limiter

New returns a Limiter that allows up to `burst` events per key over `per`, with steady-state refill at `burst/per`. evictAfter is the inactivity window after which a key's bucket is forgotten — pick something larger than `per` so genuine retries don't reset their bucket.

The bucket map is capped at DefaultMaxBuckets entries. Operators that need a different cap can construct via NewWithCap.

func NewWithCap

func NewWithCap(burst int, per, evictAfter time.Duration, maxBuckets int) *Limiter

NewWithCap is New with an explicit ceiling on the per-key map size.

func (*Limiter) Allow

func (l *Limiter) Allow(key string) bool

Allow returns true if the supplied key can perform one event under the current bucket state. Side-effect: the bucket is created on first use and idle buckets are GC'd opportunistically (at most once per evictInterval to keep the hot path constant-time). When the map is already at maxBuckets and the key has no existing bucket, the call falls back to the shared overflow bucket so memory stays bounded.

func (*Limiter) HTTPMiddleware

func (l *Limiter) HTTPMiddleware(keyFn func(*http.Request) string, onReject func(*http.Request, string)) func(http.Handler) http.Handler

HTTPMiddleware returns a middleware that rejects requests with 429 when `keyFn(r)` exceeds the limit. keyFn is responsible for choosing the dimension (e.g., utils.GetIP(r), or `utils.GetIP(r) + ":" + username`).

onReject is invoked synchronously when a request is rejected — use it to emit an audit-log entry. May be nil.

Jump to

Keyboard shortcuts

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