2e9e8997

By: Michael Lynch <git@mtlynch.io>

Add per-email and per-IPv4 login rate limiting

Replace the global 20-attempt login rate limiter with independent
per-email (max 2) and per-IPv4 (max 4) limits within a 24-hour
sliding window. IPv6 addresses are only limited by email, not by IP.

Thread the client IP from the HTTP request through a new
LoginEmailRequest struct so the rate limiter can enforce IP-based
limits. Extract the client IP from r.RemoteAddr, handling both
"host:port" and bare IP formats. Normalize IPv4-mapped IPv6
addresses (::ffff:x.x.x.x) to their native IPv4 form for
consistent rate limiting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Suite timing

Time to Start Worker time Duration Time to finish Idle
Config 19s 10s 10s 29s 19s
Eval 28s 2m01s 2m01s 2m30s 0s
Build 46s 8m54s 1m40s 2m27s 0s
Suite 19s 11m06s 2m10s 2m30s 19s

Timeline

0s20s30s40s50s1m1m10s1m20s1m30s1m40s1m50s2m2m10s2m20s2m30s