Add Certificates page and Traefik API frontend client

This commit is contained in:
backup 2026-09-02 12:42:52 -05:00
commit 7fc90524b5
40 changed files with 6585 additions and 359 deletions

View file

@ -0,0 +1,70 @@
package auth
import (
"sync"
"time"
)
// LoginRateLimiter tracks failed login attempts per key (IP or username) and enforces backoff.
type LoginRateLimiter struct {
mu sync.Mutex
attempts map[string][]time.Time
// config
maxAttempts int
window time.Duration
blockDuration time.Duration
}
func NewLoginRateLimiter(maxAttempts int, window time.Duration, blockDuration time.Duration) *LoginRateLimiter {
return &LoginRateLimiter{
attempts: make(map[string][]time.Time),
maxAttempts: maxAttempts,
window: window,
blockDuration: blockDuration,
}
}
// Allow returns true if the key is allowed to attempt login now.
// It also cleans up old entries.
func (r *LoginRateLimiter) Allow(key string) bool {
r.mu.Lock()
defer r.mu.Unlock()
now := time.Now()
times := r.attempts[key]
// filter within window
var filtered []time.Time
for _, t := range times {
if now.Sub(t) < r.window {
filtered = append(filtered, t)
}
}
r.attempts[key] = filtered
if len(filtered) >= r.maxAttempts {
// Check if still within block duration from last attempt
last := filtered[len(filtered)-1]
if now.Sub(last) < r.blockDuration {
return false
}
// block expired, allow and reset
r.attempts[key] = nil
return true
}
return true
}
// RecordFailure records a failed attempt for key.
func (r *LoginRateLimiter) RecordFailure(key string) {
r.mu.Lock()
defer r.mu.Unlock()
r.attempts[key] = append(r.attempts[key], time.Now())
}
// RecordSuccess clears failures for key.
func (r *LoginRateLimiter) RecordSuccess(key string) {
r.mu.Lock()
defer r.mu.Unlock()
delete(r.attempts, key)
}
// DefaultLoginLimiter is a global limiter: 5 failures per minute, block for 30s after
var DefaultLoginLimiter = NewLoginRateLimiter(5, time.Minute, 30*time.Second)