From 1a531af4f8fbfaa87ec204d31433c8cba1633d9e Mon Sep 17 00:00:00 2001 From: H3ALY Date: Tue, 25 Mar 2025 15:12:56 +0000 Subject: [PATCH] implement rate limiting --- go.mod | 1 + go.sum | 2 ++ helpers/ratelimit.go | 35 +++++++++++++++++++++++++++++++++++ main.go | 3 ++- 4 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 helpers/ratelimit.go diff --git a/go.mod b/go.mod index b21fe98..b42a2ba 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/gorilla/sessions v1.4.0 golang.org/x/crypto v0.36.0 modernc.org/sqlite v1.36.1 + golang.org/x/time v0.11.0 ) require ( diff --git a/go.sum b/go.sum index 39a5de3..76e49a6 100644 --- a/go.sum +++ b/go.sum @@ -29,6 +29,8 @@ golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= +golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= modernc.org/cc/v4 v4.24.4 h1:TFkx1s6dCkQpd6dKurBNmpo+G8Zl4Sq/ztJ+2+DEsh0= diff --git a/helpers/ratelimit.go b/helpers/ratelimit.go new file mode 100644 index 0000000..08f219c --- /dev/null +++ b/helpers/ratelimit.go @@ -0,0 +1,35 @@ +package helpers + +import ( + "net" + "net/http" + "sync" + + "golang.org/x/time/rate" +) + +var visitors = make(map[string]*rate.Limiter) +var mu sync.Mutex + +func GetVisitorLimiter(ip string) *rate.Limiter { + mu.Lock() + defer mu.Unlock() + + limiter, exists := visitors[ip] + if !exists { + limiter = rate.NewLimiter(1, 5) + visitors[ip] = limiter + } + return limiter +} + +func RateLimit(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ip, _, _ := net.SplitHostPort(r.RemoteAddr) + if !GetVisitorLimiter(ip).Allow() { + http.Error(w, "Too many requests", http.StatusTooManyRequests) + return + } + next.ServeHTTP(w, r) + }) +} diff --git a/main.go b/main.go index 0304697..4797d94 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,7 @@ import ( "log" "net/http" "synlotto-website/handlers" + "synlotto-website/helpers" "synlotto-website/models" "synlotto-website/storage" @@ -35,5 +36,5 @@ func main() { mux.HandleFunc("/results/thunderball", handlers.ResultsThunderball(db)) log.Println("🌐 Running on http://localhost:8080") - http.ListenAndServe(":8080", csrfMiddleware(mux)) + http.ListenAndServe(":8080", helpers.RateLimit(csrfMiddleware(mux))) }