Brijesh's Git Server — watchman @ fa969251d72ae021889eb25e4a6b4fa69c468b21

observability tool, needs to be rewritten once identity is stable

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
commit

fa969251d72ae021889eb25e4a6b4fa69c468b21

parent

f57775c9d4697979ab959a360971d36dc91b178b

3 files changed, 58 insertions(+), 4 deletions(-)

jump to
M config.yamlconfig.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.gomiddleware/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",