mirror of
https://github.com/Theodor-Springmann-Stiftung/musenalm.git
synced 2025-10-29 01:05:32 +00:00
rate limit
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/Theodor-Springmann-Stiftung/musenalm/app"
|
"github.com/Theodor-Springmann-Stiftung/musenalm/app"
|
||||||
"github.com/Theodor-Springmann-Stiftung/musenalm/dbmodels"
|
"github.com/Theodor-Springmann-Stiftung/musenalm/dbmodels"
|
||||||
"github.com/Theodor-Springmann-Stiftung/musenalm/helpers/security"
|
"github.com/Theodor-Springmann-Stiftung/musenalm/helpers/security"
|
||||||
|
"github.com/Theodor-Springmann-Stiftung/musenalm/middleware"
|
||||||
"github.com/Theodor-Springmann-Stiftung/musenalm/pagemodels"
|
"github.com/Theodor-Springmann-Stiftung/musenalm/pagemodels"
|
||||||
"github.com/Theodor-Springmann-Stiftung/musenalm/templating"
|
"github.com/Theodor-Springmann-Stiftung/musenalm/templating"
|
||||||
"github.com/pocketbase/pocketbase/core"
|
"github.com/pocketbase/pocketbase/core"
|
||||||
@@ -48,7 +49,8 @@ type LoginPage struct {
|
|||||||
|
|
||||||
func (p *LoginPage) Setup(router *router.Router[*core.RequestEvent], app core.App, engine *templating.Engine) error {
|
func (p *LoginPage) Setup(router *router.Router[*core.RequestEvent], app core.App, engine *templating.Engine) error {
|
||||||
router.GET(URL_LOGIN, p.GET(engine, app))
|
router.GET(URL_LOGIN, p.GET(engine, app))
|
||||||
router.POST(URL_LOGIN, p.POST(engine, app))
|
r := router.POST(URL_LOGIN, p.POST(engine, app))
|
||||||
|
r.BindFunc(middleware.RateLimiter(30, time.Minute*2, time.Hour*6))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
74
middleware/rate-limiter.go
Normal file
74
middleware/rate-limiter.go
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
type clientStats struct {
|
||||||
|
count int
|
||||||
|
windowStart time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func RateLimiter(limit int, windowDuration time.Duration, cleanupInterval time.Duration) func(*core.RequestEvent) error {
|
||||||
|
clientRequests := make(map[string]*clientStats)
|
||||||
|
var mu sync.Mutex
|
||||||
|
|
||||||
|
startPeriodicCleanup(clientRequests, &mu, windowDuration, cleanupInterval)
|
||||||
|
|
||||||
|
return func(e *core.RequestEvent) error {
|
||||||
|
if e == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ipStr := e.RealIP()
|
||||||
|
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
|
||||||
|
stats, exists := clientRequests[ipStr]
|
||||||
|
now := time.Now()
|
||||||
|
|
||||||
|
if !exists || now.After(stats.windowStart.Add(windowDuration)) {
|
||||||
|
clientRequests[ipStr] = &clientStats{
|
||||||
|
count: 1,
|
||||||
|
windowStart: now,
|
||||||
|
}
|
||||||
|
return e.Next()
|
||||||
|
}
|
||||||
|
|
||||||
|
if stats.count >= limit {
|
||||||
|
return e.Error(http.StatusTooManyRequests, "Too Many Requests", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
stats.count++
|
||||||
|
return e.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func performCleanupCycle(clientRequests map[string]*clientStats, mu *sync.Mutex, windowDuration time.Duration) {
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
maxEntryAge := 2 * windowDuration
|
||||||
|
for ip, stats := range clientRequests {
|
||||||
|
if now.After(stats.windowStart.Add(maxEntryAge)) {
|
||||||
|
delete(clientRequests, ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func startPeriodicCleanup(clientRequests map[string]*clientStats, mu *sync.Mutex, windowDuration time.Duration, cleanupInterval time.Duration) {
|
||||||
|
go func() {
|
||||||
|
ticker := time.NewTicker(cleanupInterval)
|
||||||
|
defer ticker.Stop() // Stop the ticker when this goroutine exits (though it runs indefinitely here)
|
||||||
|
|
||||||
|
for range ticker.C {
|
||||||
|
performCleanupCycle(clientRequests, mu, windowDuration)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user