Skip to content

Commit

Permalink
added method to return useful headers when hitting rate limit
Browse files Browse the repository at this point in the history
  • Loading branch information
jeppekroghitk committed May 28, 2024
1 parent 0f74da5 commit 9f3e9bb
Showing 1 changed file with 37 additions and 6 deletions.
43 changes: 37 additions & 6 deletions app/Core/Middleware/RequestRateLimiter.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

use Closure;
use Illuminate\Cache\RateLimiter;
use Illuminate\Contracts\Container\BindingResolutionException;
use Illuminate\Support\Facades\Cache;
use Leantime\Core\ApiRequest;
use Leantime\Core\Environment;
use Leantime\Core\Eventhelpers;
use Leantime\Core\Frontcontroller;
use Leantime\Core\IncomingRequest;
Expand Down Expand Up @@ -41,29 +43,34 @@ public function __construct()
* Handle the incoming request.
*
* @param IncomingRequest $request The incoming request object.
* @param Closure $next The next middleware closure.
* @param Closure $next The next middleware closure.
* @return Response The response object.
* @throws BindingResolutionException
*/
public function handle(IncomingRequest $request, Closure $next): Response
{
//Configurable rate limits
$LEAN_RATELIMIT_GENERAL = app()->make(Environment::class)->get('LEAN_RATELIMIT_GENERAL') ?? 1000;
$LEAN_RATELIMIT_API = app()->make(Environment::class)->get('LEAN_RATELIMIT_API') ?? 10;
$LEAN_RATELIMIT_AUTH = app()->make(Environment::class)->get('LEAN_RATELIMIT_AUTH') ?? 20;

//Key
$key = $request->getClientIp();

//General Limit per minute
$limit = 1000;
$limit = $LEAN_RATELIMIT_GENERAL;

//API Routes Limit
if ($request instanceof ApiRequest) {
$apiKey = "";
$key = app()->make(Api::class)->getAPIKeyUser($apiKey);
$limit = 10;
$limit = $LEAN_RATELIMIT_API;
}

$route = Frontcontroller::getCurrentRoute();

if ($route == "auth.login") {
$limit = 20;
$limit = $LEAN_RATELIMIT_AUTH;
$key = $key . ".loginAttempts";
}

Expand All @@ -83,13 +90,37 @@ public function handle(IncomingRequest $request, Closure $next): Response
"key" => $key,
],
);

if ($this->limiter->tooManyAttempts($key, $limit)) {
error_log("too many requests per minute: " . $key);
return new Response(json_encode(['error' => 'Too many requests per minute.']), Response::HTTP_TOO_MANY_REQUESTS);
return new Response(
json_encode(['error' => 'Too many requests per minute.']),
Response::HTTP_TOO_MANY_REQUESTS,
$this->getHeaders($key, $limit),
);
}

$this->limiter->hit($key, 60);

return $next($request);
}


/**
* Get rate limiter headers for response.
*
* @param string $key
*
* @param string $limit
*
* @return array
*/
private function getHeaders(string $key, string $limit): array
{
return [
'X-RateLimit-Remaining' => $this->limiter->retriesLeft($key, $limit),
'X-RateLimit-Retry-After' => $this->limiter->availableIn($key),
'X-RateLimit-Limit' => $this->limiter->attempts($key),
'X-RateLimit-type' => $key,
];
}
}

0 comments on commit 9f3e9bb

Please sign in to comment.