package main import ( "net" "net/http" "sync" "time" ) type rateLimiter struct { mu sync.Mutex counts map[string][]time.Time limit int window time.Duration } func newRateLimiter(limit int, window time.Duration) *rateLimiter { return &rateLimiter{ counts: make(map[string][]time.Time), limit: limit, window: window, } } func (rl *rateLimiter) Allow(key string) bool { rl.mu.Lock() defer rl.mu.Unlock() now := time.Now() windowStart := now.Add(-rl.window) timestamps := rl.counts[key] filtered := timestamps[:0] for _, t := range timestamps { if t.After(windowStart) { filtered = append(filtered, t) } } if len(filtered) >= rl.limit { rl.counts[key] = filtered return false } rl.counts[key] = append(filtered, now) return true } var ( authLimiter = newRateLimiter(20, time.Minute) changeLimiter = newRateLimiter(10, time.Minute) lostLimiter = newRateLimiter(5, time.Minute) resetLimiter = newRateLimiter(10, time.Minute) aliasLimiter = newRateLimiter(30, time.Minute) ) func remoteIP(r *http.Request) string { host, _, err := net.SplitHostPort(r.RemoteAddr) if err != nil { return r.RemoteAddr } return host }