feat(rate limiting): make rate limiting req/sec configurable add rate limiting variable in config.yaml file to make it easier to edit if needed
Brijesh ops@brijesh.dev
Tue, 09 Jul 2024 17:45:20 +0530
3 files changed,
58 insertions(+),
4 deletions(-)
M
config.yaml
→
config.yaml
@@ -1,1 +1,9 @@
port: 4000 + +admin: + username: "admin" + password: "admin" + +jwt_key: "my-key" + +rate_limit_req_per_sec: 5
A
middleware/auth.go
@@ -0,0 +1,46 @@
+package middleware + +import ( + "context" + "net/http" + "watchman/schema" + + "github.com/golang-jwt/jwt/v5" +) + +func AdminJwtMiddleware(config schema.ConfigType, next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + cookie, err := r.Cookie("token") + if err != nil { + if err == http.ErrNoCookie { + w.WriteHeader(http.StatusUnauthorized) + return + } + w.WriteHeader(http.StatusBadRequest) + return + } + + tokenStr := cookie.Value + claims := &schema.Claims{} + + token, err := jwt.ParseWithClaims(tokenStr, claims, func(token *jwt.Token) (interface{}, error) { + return config.JwtKey, nil + }) + if err != nil { + if err == jwt.ErrSignatureInvalid { + w.WriteHeader(http.StatusUnauthorized) + return + } + w.WriteHeader(http.StatusBadRequest) + return + } + + if !token.Valid { + w.WriteHeader(http.StatusUnauthorized) + return + } + + ctx := context.WithValue(r.Context(), schema.UsernameKey{}, claims) + next.ServeHTTP(w, r.WithContext(ctx)) + }) +}
M
middleware/rate_limiting.go
→
middleware/rate_limiting.go
@@ -26,13 +26,13 @@ mu sync.Mutex
) // Get the visitor from the visitors map based on the IP address -func getVisitor(ip string) *rate.Limiter { +func getVisitor(ip string, config schema.ConfigType) *rate.Limiter { mu.Lock() defer mu.Unlock() v, exists := visitors[ip] if !exists { - limiter := rate.NewLimiter(1, 3) + limiter := rate.NewLimiter(1, config.RateLimitRequestsPerSecond) // Include the current time when creating a new visitor visitors[ip] = &visitor{limiter, time.Now()} return limiter@@ -58,7 +58,7 @@ mu.Unlock()
} } -func Ratelimit(next http.Handler) http.Handler { +func Ratelimit(config schema.ConfigType, next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ip, _, err := net.SplitHostPort(r.RemoteAddr) if err != nil {@@ -67,7 +67,7 @@ http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return } - limiter := getVisitor(ip) + limiter := getVisitor(ip, config) if !limiter.Allow() { response := schema.Response_Type{ Status: "ERROR",