diff --git a/README.md b/README.md index e411ad2..2088e9c 100644 --- a/README.md +++ b/README.md @@ -41,8 +41,8 @@ vim .env # edit your config + `HOST`: (default: "localhost:3000") Host the app should listen on + `PORT`: (default: 3000) Port the app should listen on + `DEFAULT_RATE_LIMIT`: (default: 10) Requests per second rate limit -+ `STRICT_RATE_LIMIT`: (default: 10) Requests per burst rate limit (e.g. 1 request each 10 seconds) -+ `BURST_RATE_LIMIT`: (default: 1) Rate limit burst ++ `STRICT_RATE_LIMIT`: (default: 10) Requests per second rate limit for resource-intensive APIs (e.g. sending a payment) ++ `BURST_RATE_LIMIT`: (default: 1) Specifies the maximum number of requests that can pass at the same moment + `ENABLE_PROMETHEUS`: (default: false) Enable Prometheus metrics to be exposed + `PROMETHEUS_PORT`: (default: 9092) Prometheus port (path: `/metrics`) + `WEBHOOK_URL`: Optional. Callback URL for incoming and outgoing payment events, see below. diff --git a/main.go b/main.go index 9a91f0e..8efa78a 100644 --- a/main.go +++ b/main.go @@ -8,6 +8,7 @@ import ( "net/http" "os" "os/signal" + "strconv" "sync" "time" @@ -125,7 +126,8 @@ func main() { } e.Use(middleware.Recover()) e.Use(middleware.BodyLimit("250K")) - e.Use(middleware.RateLimiter(middleware.NewRateLimiterMemoryStore(20))) + // set the default rate limit defining the overal max requests/second + e.Use(middleware.RateLimiter(middleware.NewRateLimiterMemoryStore(rate.Limit(c.DefaultRateLimit)))) e.Logger = logger e.Use(middleware.RequestID()) @@ -184,8 +186,9 @@ func main() { InvoicePubSub: service.NewPubsub(), } + // strict rate limit for requests for sending payments strictRateLimitMiddleware := createRateLimitMiddleware(c.StrictRateLimit, c.BurstRateLimit) - secured := e.Group("", tokens.Middleware(c.JWTSecret), middleware.RateLimiter(middleware.NewRateLimiterMemoryStore(rate.Limit(c.DefaultRateLimit)))) + secured := e.Group("", tokens.Middleware(c.JWTSecret)) securedWithStrictRateLimit := e.Group("", tokens.Middleware(c.JWTSecret), strictRateLimitMiddleware) RegisterLegacyEndpoints(svc, e, secured, securedWithStrictRateLimit, strictRateLimitMiddleware, tokens.AdminTokenMiddleware(c.AdminToken)) @@ -304,12 +307,24 @@ func main() { svc.Logger.Info("LNDhub exiting gracefully. Goodbye.") } -func createRateLimitMiddleware(seconds int, burst int) echo.MiddlewareFunc { - config := middleware.RateLimiterMemoryStoreConfig{ - Rate: rate.Every(time.Duration(seconds) * time.Second), - Burst: burst, +func createRateLimitMiddleware(requestsPerSecond int, burst int) echo.MiddlewareFunc { + config := middleware.RateLimiterConfig{ + Store: middleware.NewRateLimiterMemoryStoreWithConfig( + middleware.RateLimiterMemoryStoreConfig{Rate: rate.Limit(requestsPerSecond), Burst: burst}, + ), + IdentifierExtractor: func(ctx echo.Context) (string, error) { + userId := ctx.Get("UserID") + id := ctx.RealIP() + if userId != nil { + userIdAsInt64 := ctx.Get("UserID").(int64) + id = strconv.FormatInt(userIdAsInt64, 10) + } + + return id, nil + }, } - return middleware.RateLimiter(middleware.NewRateLimiterMemoryStoreWithConfig(config)) + + return middleware.RateLimiterWithConfig(config) } func createCacheClient() *cache.Client {