feat: add rate limiting to feed endpoint and update route paths

- Implement per-client rate limiting (5 requests per 3 seconds)
- Change /channel/:id routes to /feed/:id for consistency
- Add data/ to .gitignore
- Include RateLimit middleware on GET /feed/:id endpoint
This commit is contained in:
2026-03-11 00:36:40 +03:30
parent e4877ce0d0
commit ee5534a2ce
3 changed files with 50 additions and 4 deletions
+2 -1
View File
@@ -1,3 +1,4 @@
.env
.vscode/launch.json
main
main
data/
+2 -3
View File
@@ -44,13 +44,12 @@ func RegisterRoutes(params RouterParams) {
})
})
// params.GinEngine.GET("/channel/:id/json", params.ChannelHandler.GetMessagesJson)
params.GinEngine.GET("/channel/:id", params.ChannelHandler.GetMessagesRSS)
// params.GinEngine.GET("/feed/:id/json", params.ChannelHandler.GetMessagesJson)
params.GinEngine.GET("/feed/:id", RateLimit(), params.ChannelHandler.GetMessagesRSS)
// TODO: improve accurecy in rss channel fields
// TODO: add ui with templates under /setup with fetch
// TODO: add gin level cache (look for higher limit)
// TODO: add gin level ip ratelimit
// TODO: image endpoint + hash and expiry
authStatCtx, cancel := context.WithTimeout(context.Background(), config.AuthStatusTimeout)
defer cancel()
+46
View File
@@ -0,0 +1,46 @@
package server
import (
"sync"
"time"
"github.com/gin-gonic/gin"
"golang.org/x/time/rate"
)
type ClientLimiter struct {
limiter *rate.Limiter
lastSeen time.Time
}
var clients = map[string]*ClientLimiter{}
var mu sync.Mutex
func getLimiter(ip string) *rate.Limiter {
mu.Lock()
defer mu.Unlock()
if c, ok := clients[ip]; ok {
c.lastSeen = time.Now()
return c.limiter
}
limiter := rate.NewLimiter(rate.Every(time.Second * 3), 5) // TODO: get from config
clients[ip] = &ClientLimiter{limiter: limiter, lastSeen: time.Now()}
return limiter
}
func RateLimit() gin.HandlerFunc {
return func(c *gin.Context) {
ip := c.ClientIP()
limiter := getLimiter(ip)
if !limiter.Allow() {
c.AbortWithStatusJSON(429, gin.H{"error": "Slow down pls"})
return
}
c.Next()
}
}