FDN-01: repository & projektgerüst

Git-Repository für bestehenden archivdms-Code initialisiert, Branch-/Commit-Konvention (feature/<ticket>-<slug>-Branches, Ticket-Prefix in Commit-Nachricht) etabliert.
This commit is contained in:
2026-08-11 21:27:53 +02:00
parent 40ed80da71
commit 9a24ea29e1
274 changed files with 53708 additions and 0 deletions
+70
View File
@@ -0,0 +1,70 @@
package auth
import (
"sync"
"time"
)
// keyedRateLimiter is a minimal in-memory token-bucket limiter keyed by an
// arbitrary string (used for per-(tenant,loginName) and per-IP LDAP login
// throttling). No external dependency, no Redis — buckets are created lazily
// and idle ones are swept periodically to bound memory.
type keyedRateLimiter struct {
mu sync.Mutex
buckets map[string]*bucket
burst float64
refillPerSec float64
lastSweep time.Time
}
type bucket struct {
tokens float64
last time.Time
}
func newKeyedRateLimiter(burst, refillPerSec float64) *keyedRateLimiter {
return &keyedRateLimiter{
buckets: make(map[string]*bucket),
burst: burst,
refillPerSec: refillPerSec,
lastSweep: time.Now(),
}
}
// allow consumes one token for key, returning false when the bucket is empty.
func (l *keyedRateLimiter) allow(key string) bool {
now := time.Now()
l.mu.Lock()
defer l.mu.Unlock()
l.sweepLocked(now)
b, ok := l.buckets[key]
if !ok {
b = &bucket{tokens: l.burst, last: now}
l.buckets[key] = b
}
b.tokens += now.Sub(b.last).Seconds() * l.refillPerSec
if b.tokens > l.burst {
b.tokens = l.burst
}
b.last = now
if b.tokens < 1 {
return false
}
b.tokens--
return true
}
func (l *keyedRateLimiter) sweepLocked(now time.Time) {
if now.Sub(l.lastSweep) < time.Minute {
return
}
l.lastSweep = now
for k, b := range l.buckets {
if now.Sub(b.last) > 30*time.Minute {
delete(l.buckets, k)
}
}
}