All checks were successful
check / check (push) Successful in 6s
## Summary Adds per-IP rate limiting to `POST /api/v1/login` to prevent brute-force password attacks. closes #35 ## What Changed ### New package: `internal/ratelimit/` A generic per-key token-bucket rate limiter built on `golang.org/x/time/rate`: - `New(ratePerSec, burst)` creates a limiter with automatic background cleanup of stale entries - `Allow(key)` checks if a request from the given key should be permitted - `Stop()` terminates the background sweep goroutine - Stale entries (unused for 15 minutes) are pruned every 10 minutes ### Login handler integration The login handler (`internal/handlers/auth.go`) now: 1. Extracts the client IP from `X-Forwarded-For`, `X-Real-IP`, or `RemoteAddr` 2. Checks the per-IP rate limiter before processing the login 3. Returns **429 Too Many Requests** with a `Retry-After: 1` header when the limit is exceeded ### Configuration Two new environment variables (via Viper): | Variable | Default | Description | |---|---|---| | `LOGIN_RATE_LIMIT` | `1` | Allowed login attempts per second per IP | | `LOGIN_RATE_BURST` | `5` | Maximum burst of login attempts per IP | ### Scope Per [sneak's instruction](#35), only the login endpoint is rate-limited. Session creation and registration use hashcash proof-of-work instead. ## Tests - 6 unit tests for the `ratelimit` package (constructor, burst, burst exceeded, key isolation, key tracking, stop) - 2 integration tests in `api_test.go`: - `TestLoginRateLimitExceeded`: exhausts burst with rapid requests, verifies 429 response and `Retry-After` header - `TestLoginRateLimitAllowsNormalUse`: verifies normal login still works ## README - Added "Login Rate Limiting" subsection under "Rate Limiting & Abuse Prevention" - Added `LOGIN_RATE_LIMIT` and `LOGIN_RATE_BURST` to the Configuration table Co-authored-by: clawbot <clawbot@noreply.git.eeqj.de> Reviewed-on: #78 Co-authored-by: clawbot <clawbot@noreply.example.org> Co-committed-by: clawbot <clawbot@noreply.example.org>
60 lines
2.3 KiB
Modula-2
60 lines
2.3 KiB
Modula-2
module git.eeqj.de/sneak/neoirc
|
|
|
|
go 1.24.0
|
|
|
|
require (
|
|
github.com/99designs/basicauth-go v0.0.0-20230316000542-bf6f9cbbf0f8
|
|
github.com/gdamore/tcell/v2 v2.13.8
|
|
github.com/getsentry/sentry-go v0.42.0
|
|
github.com/go-chi/chi/v5 v5.2.1
|
|
github.com/go-chi/cors v1.2.2
|
|
github.com/google/uuid v1.6.0
|
|
github.com/joho/godotenv v1.5.1
|
|
github.com/prometheus/client_golang v1.23.2
|
|
github.com/rivo/tview v0.42.0
|
|
github.com/slok/go-http-metrics v0.13.0
|
|
github.com/spf13/viper v1.21.0
|
|
go.uber.org/fx v1.24.0
|
|
golang.org/x/crypto v0.48.0
|
|
golang.org/x/time v0.6.0
|
|
modernc.org/sqlite v1.45.0
|
|
)
|
|
|
|
require (
|
|
github.com/beorn7/perks v1.0.1 // indirect
|
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
|
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
|
github.com/gdamore/encoding v1.0.1 // indirect
|
|
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
|
github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
|
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
|
github.com/ncruces/go-strftime v1.0.0 // indirect
|
|
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
|
github.com/prometheus/client_model v0.6.2 // indirect
|
|
github.com/prometheus/common v0.66.1 // indirect
|
|
github.com/prometheus/procfs v0.16.1 // indirect
|
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
|
github.com/rivo/uniseg v0.4.7 // indirect
|
|
github.com/sagikazarmark/locafero v0.11.0 // indirect
|
|
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
|
|
github.com/spf13/afero v1.15.0 // indirect
|
|
github.com/spf13/cast v1.10.0 // indirect
|
|
github.com/spf13/pflag v1.0.10 // indirect
|
|
github.com/subosito/gotenv v1.6.0 // indirect
|
|
go.uber.org/dig v1.19.0 // indirect
|
|
go.uber.org/multierr v1.10.0 // indirect
|
|
go.uber.org/zap v1.26.0 // indirect
|
|
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
|
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
|
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect
|
|
golang.org/x/sys v0.41.0 // indirect
|
|
golang.org/x/term v0.40.0 // indirect
|
|
golang.org/x/text v0.34.0 // indirect
|
|
google.golang.org/protobuf v1.36.8 // indirect
|
|
modernc.org/libc v1.67.6 // indirect
|
|
modernc.org/mathutil v1.7.1 // indirect
|
|
modernc.org/memory v1.11.0 // indirect
|
|
)
|