1<?php
2
3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0.
4// See the LICENCE file in the repository root for full licence text.
5
6namespace App\Http\Middleware;
7
8use App\Libraries\RateLimiter;
9use Closure;
10use Illuminate\Routing\Middleware\ThrottleRequests as ThrottleRequestsBase;
11
12class ThrottleRequests extends ThrottleRequestsBase
13{
14 public function __construct(RateLimiter $limiter)
15 {
16 parent::__construct($limiter);
17 }
18
19 public static function getApiThrottle($group = 'global')
20 {
21 return 'throttle:'.$GLOBALS['cfg']['osu']['api']['throttle'][$group].':';
22 }
23
24 protected function handleRequest($request, Closure $next, array $limits)
25 {
26 foreach ($limits as $limit) {
27 if ($this->limiter->tooManyAttempts($limit->key, $limit->maxAttempts)) {
28 throw $this->buildException($request, $limit->key, $limit->maxAttempts, $limit->responseCallback);
29 }
30 }
31
32 $response = $next($request);
33
34 $cost = RequestCost::getCost($request);
35
36 foreach ($limits as $limit) {
37 // hit moved to after request is processed to be able to get the cost assigned by the controller action,
38 // in constrast to the original function. This works fine since $next will handle exceptions
39 // thrown by the controller so the rest of the function still runs.
40 $this->limiter->hit($limit->key, $limit->decayMinutes * 60, $cost);
41
42 $response = $this->addHeaders(
43 $response,
44 $limit->maxAttempts,
45 $this->calculateRemainingAttempts($limit->key, $limit->maxAttempts)
46 );
47 }
48
49 return $response;
50 }
51
52 protected function resolveRequestSignature($request)
53 {
54 $token = oauth_token();
55 if ($token !== null) {
56 return sha1($token->getKey());
57 }
58
59 return parent::resolveRequestSignature($request);
60 }
61}