mirror of
https://github.com/lightninglabs/aperture.git
synced 2026-01-31 15:14:26 +01:00
Implement a token-bucket rate limiter for aperture that limits requests per service endpoint. The rate limiter uses golang.org/x/time/rate and provides per-key limiting with L402 token ID extraction (falling back to IP address for unauthenticated requests). Key components: - RateLimitConfig: Configuration struct with path regex, requests/per/burst - RateLimiter: Manages per-key rate.Limiter instances with LRU eviction to prevent memory exhaustion (default 10,000 entries) - Prometheus metrics: allowed/denied counters, cache size, evictions This addresses GitHub issue #200 for DoS protection on authenticated endpoints that are free of charge after L402 payment.
57 lines
1.7 KiB
Go
57 lines
1.7 KiB
Go
package proxy
|
|
|
|
import (
|
|
"regexp"
|
|
"time"
|
|
)
|
|
|
|
// RateLimitConfig defines a rate limiting rule for a specific path pattern.
|
|
type RateLimitConfig struct {
|
|
// PathRegexp is a regular expression that matches request paths
|
|
// to which this rate limit applies. If empty, matches all paths.
|
|
PathRegexp string `long:"pathregexp" description:"Regular expression to match the path of the URL against for rate limiting"`
|
|
|
|
// Requests is the number of requests allowed per time window (Per).
|
|
Requests int `long:"requests" description:"Number of requests allowed per time window"`
|
|
|
|
// Per is the time window duration (e.g., 1s, 1m, 1h). Defaults to 1s.
|
|
Per time.Duration `long:"per" description:"Time window for rate limiting (e.g., 1s, 1m, 1h)"`
|
|
|
|
// Burst is the maximum number of requests that can be made in a burst,
|
|
// exceeding the steady-state rate. Defaults to Requests if not set.
|
|
Burst int `long:"burst" description:"Maximum burst size (defaults to Requests if not set)"`
|
|
|
|
// compiledPathRegexp is the compiled version of PathRegexp.
|
|
compiledPathRegexp *regexp.Regexp
|
|
}
|
|
|
|
// Rate returns the rate.Limit value (requests per second) for this
|
|
// configuration.
|
|
func (r *RateLimitConfig) Rate() float64 {
|
|
if r.Per == 0 {
|
|
return 0
|
|
}
|
|
|
|
return float64(r.Requests) / r.Per.Seconds()
|
|
}
|
|
|
|
// EffectiveBurst returns the burst value, defaulting to Requests if Burst
|
|
// is 0.
|
|
func (r *RateLimitConfig) EffectiveBurst() int {
|
|
if r.Burst == 0 {
|
|
return r.Requests
|
|
}
|
|
|
|
return r.Burst
|
|
}
|
|
|
|
// Matches returns true if the given path matches this rate limit's path
|
|
// pattern.
|
|
func (r *RateLimitConfig) Matches(path string) bool {
|
|
if r.compiledPathRegexp == nil {
|
|
return true // No pattern means match all
|
|
}
|
|
|
|
return r.compiledPathRegexp.MatchString(path)
|
|
}
|