This repository has been archived on 2026-04-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
core/server/middleware/ratelimit.go
Jeffrey Smith f0dd43144e rebrand: Switchboard Core → Armature
- Rename Go module switchboard-core → armature (155+ files)
- Rename Docker image → gobha/armature
- Rename K8s resources, secrets, deployments
- Rename Prometheus metrics switchboard_* → armature_*
- Rename env vars SWITCHBOARD_ADMIN_* → ARMATURE_ADMIN_*
- Rename DB names switchboard_core* → armature*
- Update all frontend branding, notification templates, docs
- Update CI scripts, e2e tests, Keycloak realm, nginx conf
- Rename scripts/switchboard-ca.sh → scripts/armature-ca.sh
- Rename k8s/switchboard.yaml → k8s/armature.yaml
- Rename chart alerting/dashboard files
- Fix: DockerHub push uses env: binding for secret injection
- Helm chart updated (name, labels, template functions, dashboard, alerting)
- Replace favicon/icon assets with Armature brand

No functional changes. Pure mechanical rename + CI fix.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 21:39:58 +00:00

53 lines
1.3 KiB
Go

package middleware
import (
"log"
"net/http"
"github.com/gin-gonic/gin"
"armature/store"
)
// RateLimiter implements per-IP rate limiting backed by a shared store.
//
// Fail-open: if the store is unavailable (PG down), requests are allowed.
// Auth endpoints have their own protections (bcrypt, lockout); blocking
// legitimate logins due to a rate-limit DB failure is worse than a brief burst.
type RateLimiter struct {
store store.RateLimitStore
rate float64
burst int
}
// NewRateLimiter creates a rate limiter backed by the given store.
// rate is requests per second, burst is max requests per window.
func NewRateLimiter(s store.RateLimitStore, rate float64, burst int) *RateLimiter {
return &RateLimiter{store: s, rate: rate, burst: burst}
}
// Limit returns a Gin middleware that enforces the rate limit.
func (rl *RateLimiter) Limit() gin.HandlerFunc {
return func(c *gin.Context) {
key := "auth:" + c.ClientIP()
allowed, err := rl.store.Allow(c.Request.Context(), key, rl.rate, rl.burst)
if err != nil {
// Fail open — don't block auth on rate limit DB failure.
log.Printf("[ratelimit] store error (allowing request): %v", err)
c.Next()
return
}
if !allowed {
c.Header("Retry-After", "1")
c.AbortWithStatusJSON(http.StatusTooManyRequests, gin.H{
"error": "rate limit exceeded",
})
return
}
c.Next()
}
}