- server: relay storing signed objects (PUT/GET), per-IP rate limiting, per-subject quota (1000), one-response-per-request, pagination, /v1/healthz /v1/readyz /v1/metrics - verify: signature-verifying trust evaluator; every object is checked via env.Verify(), approvals via VerifyApprovalResponse, revocations via VerifyRevocationOf; k-of-n approval quorum - docs: TRUST-MODEL.md and API.md describing issuer-anchored signatures and the endpoint/status-code contract - tests: server, verify, and ratelimit packages
60 lines
1.3 KiB
Go
60 lines
1.3 KiB
Go
package server
|
|
|
|
import (
|
|
"net"
|
|
"net/http"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// ipLimiter is a fixed-window per-client rate limiter keyed by remote IP. It is
|
|
// deliberately minimal: no bursting, no warm-up, just a hard cap per window to
|
|
// keep an open relay from being flooded.
|
|
type ipLimiter struct {
|
|
mu sync.Mutex
|
|
limit int
|
|
window time.Duration
|
|
hits map[string]int
|
|
reset map[string]time.Time
|
|
}
|
|
|
|
func newIPLimiter(limit int, window time.Duration) *ipLimiter {
|
|
return &ipLimiter{
|
|
limit: limit,
|
|
window: window,
|
|
hits: make(map[string]int),
|
|
reset: make(map[string]time.Time),
|
|
}
|
|
}
|
|
|
|
// allow reports whether the client may proceed, incrementing its windowed count.
|
|
func (l *ipLimiter) allow(ip string) bool {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
now := time.Now()
|
|
until, ok := l.reset[ip]
|
|
if !ok || now.After(until) {
|
|
l.hits[ip] = 0
|
|
l.reset[ip] = now.Add(l.window)
|
|
} else if now.Sub(until) > l.window*2 {
|
|
// Lazy cleanup of long-idle entries.
|
|
delete(l.hits, ip)
|
|
delete(l.reset, ip)
|
|
l.hits[ip] = 0
|
|
l.reset[ip] = now.Add(l.window)
|
|
}
|
|
if l.hits[ip] >= l.limit {
|
|
return false
|
|
}
|
|
l.hits[ip]++
|
|
return true
|
|
}
|
|
|
|
// clientIP returns the request's remote IP, stripping a port if present.
|
|
func clientIP(r *http.Request) string {
|
|
host, _, err := net.SplitHostPort(r.RemoteAddr)
|
|
if err != nil {
|
|
return r.RemoteAddr
|
|
}
|
|
return host
|
|
}
|