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>