2017-01-30 20:40:43 +01:00
|
|
|
<?php
|
2015-04-02 15:06:16 +02:00
|
|
|
|
2017-01-30 20:40:43 +01:00
|
|
|
namespace App\Http\Middleware;
|
|
|
|
|
|
|
|
use App\Models\AccountToken;
|
|
|
|
use Auth;
|
|
|
|
use Cache;
|
2015-04-02 15:06:16 +02:00
|
|
|
use Closure;
|
|
|
|
use Request;
|
|
|
|
use Response;
|
2017-01-30 20:40:43 +01:00
|
|
|
use Session;
|
|
|
|
use Utils;
|
2015-04-02 15:06:16 +02:00
|
|
|
|
2016-07-03 18:11:58 +02:00
|
|
|
/**
|
2017-01-30 20:40:43 +01:00
|
|
|
* Class ApiCheck.
|
2016-07-03 18:11:58 +02:00
|
|
|
*/
|
2017-01-30 17:05:31 +01:00
|
|
|
class ApiCheck
|
|
|
|
{
|
2015-04-02 15:06:16 +02:00
|
|
|
/**
|
2017-01-30 20:40:43 +01:00
|
|
|
* Handle an incoming request.
|
|
|
|
*
|
|
|
|
* @param \Illuminate\Http\Request $request
|
|
|
|
* @param \Closure $next
|
|
|
|
*
|
|
|
|
* @return mixed
|
|
|
|
*/
|
2015-04-02 15:06:16 +02:00
|
|
|
public function handle($request, Closure $next)
|
|
|
|
{
|
2016-10-06 14:46:27 +02:00
|
|
|
$loggingIn = $request->is('api/v1/login')
|
|
|
|
|| $request->is('api/v1/register')
|
2017-11-14 10:56:41 +01:00
|
|
|
|| $request->is('api/v1/oauth_login')
|
|
|
|
|| $request->is('api/v1/ios_subscription_status');
|
2017-01-11 09:13:22 +01:00
|
|
|
|
2015-04-02 15:06:16 +02:00
|
|
|
$headers = Utils::getApiHeaders();
|
2016-09-20 08:03:07 +02:00
|
|
|
$hasApiSecret = false;
|
2016-06-05 17:50:41 +02:00
|
|
|
|
|
|
|
if ($secret = env(API_SECRET)) {
|
2016-10-26 09:24:16 +02:00
|
|
|
$requestSecret = Request::header('X-Ninja-Secret') ?: ($request->api_secret ?: '');
|
|
|
|
$hasApiSecret = hash_equals($requestSecret, $secret);
|
2016-06-05 17:50:41 +02:00
|
|
|
}
|
2015-04-02 15:06:16 +02:00
|
|
|
|
2015-11-02 19:43:22 +01:00
|
|
|
if ($loggingIn) {
|
2016-03-08 22:22:59 +01:00
|
|
|
// check API secret
|
2017-01-30 17:05:31 +01:00
|
|
|
if (! $hasApiSecret) {
|
2016-03-08 22:22:59 +01:00
|
|
|
sleep(ERROR_DELAY);
|
2017-01-30 20:40:43 +01:00
|
|
|
$error['error'] = ['message' => 'Invalid value for API_SECRET'];
|
|
|
|
|
2017-01-11 09:13:22 +01:00
|
|
|
return Response::json($error, 403, $headers);
|
2016-03-08 22:22:59 +01:00
|
|
|
}
|
2015-04-02 15:06:16 +02:00
|
|
|
} else {
|
2015-11-02 19:43:22 +01:00
|
|
|
// check for a valid token
|
|
|
|
$token = AccountToken::where('token', '=', Request::header('X-Ninja-Token'))->first(['id', 'user_id']);
|
|
|
|
|
2016-05-08 20:50:35 +02:00
|
|
|
// check if user is archived
|
|
|
|
if ($token && $token->user) {
|
2016-08-17 16:29:25 +02:00
|
|
|
Auth::onceUsingId($token->user_id);
|
2015-11-02 19:43:22 +01:00
|
|
|
Session::set('token_id', $token->id);
|
2017-03-05 11:29:28 +01:00
|
|
|
} elseif ($hasApiSecret && $request->is('api/v1/ping')) {
|
|
|
|
// do nothing: allow ping with api_secret or account token
|
2015-11-02 19:43:22 +01:00
|
|
|
} else {
|
2016-03-08 22:22:59 +01:00
|
|
|
sleep(ERROR_DELAY);
|
2017-01-30 20:40:43 +01:00
|
|
|
$error['error'] = ['message' => 'Invalid token'];
|
|
|
|
|
2017-01-11 09:13:22 +01:00
|
|
|
return Response::json($error, 403, $headers);
|
2015-11-02 19:43:22 +01:00
|
|
|
}
|
2015-04-02 15:06:16 +02:00
|
|
|
}
|
|
|
|
|
2017-01-30 20:40:43 +01:00
|
|
|
if (! Utils::isNinja() && ! $loggingIn) {
|
2015-05-13 17:32:59 +02:00
|
|
|
return $next($request);
|
2015-04-02 15:06:16 +02:00
|
|
|
}
|
|
|
|
|
2017-01-30 20:40:43 +01:00
|
|
|
if (! Utils::hasFeature(FEATURE_API) && ! $hasApiSecret) {
|
|
|
|
$error['error'] = ['message' => 'API requires pro plan'];
|
|
|
|
|
2017-01-11 09:13:22 +01:00
|
|
|
return Response::json($error, 403, $headers);
|
2015-04-02 15:06:16 +02:00
|
|
|
} else {
|
2015-11-02 19:43:22 +01:00
|
|
|
$key = Auth::check() ? Auth::user()->account->id : $request->getClientIp();
|
2015-04-02 15:06:16 +02:00
|
|
|
|
|
|
|
// http://stackoverflow.com/questions/1375501/how-do-i-throttle-my-sites-api-users
|
|
|
|
$hour = 60 * 60;
|
2017-08-13 12:46:52 +02:00
|
|
|
$hour_limit = $hasApiSecret ? 1000 : 100; // users are limited to 100 requests/hour (or 1000 for the mobile apps)
|
2015-11-02 19:43:22 +01:00
|
|
|
$hour_throttle = Cache::get("hour_throttle:{$key}", null);
|
|
|
|
$last_api_request = Cache::get("last_api_request:{$key}", 0);
|
2015-04-02 15:06:16 +02:00
|
|
|
$last_api_diff = time() - $last_api_request;
|
2016-05-29 16:31:03 +02:00
|
|
|
|
2015-04-02 15:06:16 +02:00
|
|
|
if (is_null($hour_throttle)) {
|
|
|
|
$new_hour_throttle = 0;
|
|
|
|
} else {
|
|
|
|
$new_hour_throttle = $hour_throttle - $last_api_diff;
|
|
|
|
$new_hour_throttle = $new_hour_throttle < 0 ? 0 : $new_hour_throttle;
|
|
|
|
$new_hour_throttle += $hour / $hour_limit;
|
2017-01-30 17:05:31 +01:00
|
|
|
$hour_hits_remaining = floor(($hour - $new_hour_throttle) * $hour_limit / $hour);
|
2015-04-02 15:06:16 +02:00
|
|
|
$hour_hits_remaining = $hour_hits_remaining >= 0 ? $hour_hits_remaining : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($new_hour_throttle > $hour) {
|
|
|
|
$wait = ceil($new_hour_throttle - $hour);
|
|
|
|
sleep(1);
|
2017-01-30 20:40:43 +01:00
|
|
|
|
2015-11-08 21:34:26 +01:00
|
|
|
return Response::json("Please wait {$wait} second(s)", 403, $headers);
|
2015-04-02 15:06:16 +02:00
|
|
|
}
|
|
|
|
|
2018-02-04 10:24:43 +01:00
|
|
|
Cache::put("hour_throttle:{$key}", $new_hour_throttle, 60);
|
|
|
|
Cache::put("last_api_request:{$key}", time(), 60);
|
2015-04-02 15:06:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return $next($request);
|
|
|
|
}
|
2016-05-29 16:31:03 +02:00
|
|
|
}
|