public function __construct()
 {
     $serializedApiMethods = serialize($this->apiMethods);
     // Launch middleware
     $this->middleware('apiguard:' . $serializedApiMethods);
     // Attempt to get an authenticated user.
     $this->user = ApiGuardAuth::getUser();
     $this->response = ApiResponseBuilder::build();
 }
Example #2
0
 /**
  * Render an exception into an HTTP response.
  *
  * @param \Illuminate\Http\Request $request
  * @param \Exception               $e
  *
  * @return \Illuminate\Http\Response
  */
 public function render($request, Exception $e)
 {
     $response = ApiResponseBuilder::build();
     if ($request->json()) {
         if ($e instanceof ModelNotFoundException || $e instanceof NotFoundHttpException) {
             return $response->errorNotFound();
         }
     }
     return parent::render($request, $e);
 }
Example #3
0
 /**
  * Handle an incoming request.
  *
  * @param  Request $request
  * @param  Closure $next
  * @param null $serializedApiMethods
  * @return mixed
  * @throws Exception
  */
 public function handle(Request $request, Closure $next, $serializedApiMethods = null)
 {
     // Unserialize parameters
     if (!is_null($serializedApiMethods)) {
         $this->apiMethods = unserialize($serializedApiMethods);
     }
     // Let's instantiate the response class first
     $response = ApiResponseBuilder::build();
     // Let's get the method
     $method = $this->getRouteMethod();
     if (empty($method)) {
         // There is no method
         return $response->errorMethodNotAllowed();
     }
     // We should check if key authentication is enabled for this method
     $keyAuthentication = true;
     if (isset($this->apiMethods[$method]['keyAuthentication']) && $this->apiMethods[$method]['keyAuthentication'] === false) {
         $keyAuthentication = false;
     }
     if ($keyAuthentication === true) {
         $key = $request->header(config('apiguard.keyName', 'X-Authorization'));
         if (empty($key)) {
             // Try getting the key from elsewhere
             $key = $request->get(config('apiguard.keyName', 'X-Authorization'));
         }
         if (empty($key)) {
             // It's still empty!
             return $response->errorUnauthorized();
         }
         $apiKeyModel = App::make(config('apiguard.models.apiKey', 'Chrisbjr\\ApiGuard\\Models\\ApiKey'));
         if (!$apiKeyModel instanceof ApiKeyRepository) {
             Log::error('[ApiGuard] Your ApiKey model should be an instance of ApiKeyRepository.');
             throw new Exception("You ApiKey model should be an instance of ApiKeyRepository.");
         }
         $this->apiKey = $apiKeyModel->getByKey($key, config('apiguard.rememberApiKeyDuration', 0));
         if (empty($this->apiKey)) {
             return $response->errorUnauthorized();
         }
         // Authenticate the user of this API key
         ApiGuardAuth::authenticate($this->apiKey);
         // API key exists
         // Check level of API
         if (!empty($this->apiMethods[$method]['level'])) {
             if ($this->apiKey->level < $this->apiMethods[$method]['level']) {
                 return $response->errorForbidden();
             }
         }
     }
     $apiLog = App::make(config('apiguard.models.apiLog', 'Chrisbjr\\ApiGuard\\Models\\ApiLog'));
     if (!$apiLog instanceof ApiLogRepository) {
         Log::error('[ApiGuard] Your ApiLog model should be an instance of ApiLogRepository.');
         throw new Exception("You ApiLog model should be an instance of ApiLogRepository.");
     }
     // Then check the limits of this method
     if (!empty($this->apiMethods[$method]['limits'])) {
         if (config('apiguard.logging', true) === false) {
             Log::warning("[ApiGuard] You specified a limit in the {$method} method but API logging needs to be enabled in the configuration for this to work.");
         }
         $limits = $this->apiMethods[$method]['limits'];
         // We get key level limits first
         if ($this->apiKey != null && !empty($limits['key'])) {
             $keyLimit = !empty($limits['key']['limit']) ? $limits['key']['limit'] : 0;
             if ($keyLimit == 0 || is_integer($keyLimit) == false) {
                 Log::warning("[ApiGuard] You defined a key limit to the " . Route::currentRouteAction() . " route but you did not set a valid number for the limit variable.");
             } else {
                 if (!$this->apiKey->ignore_limits) {
                     // This means the apikey is not ignoring the limits
                     $keyIncrement = !empty($limits['key']['increment']) ? $limits['key']['increment'] : config('apiguard.keyLimitIncrement', '1 hour');
                     $keyIncrementTime = strtotime('-' . $keyIncrement);
                     if ($keyIncrementTime == false) {
                         Log::warning("[ApiGuard] You have specified an invalid key increment time. This value can be any value accepted by PHP's strtotime() method");
                     } else {
                         // Count the number of requests for this method using this api key
                         $apiLogCount = $apiLog->countApiKeyRequests($this->apiKey->id, Route::currentRouteAction(), $request->getMethod(), $keyIncrementTime);
                         if ($apiLogCount >= $keyLimit) {
                             Log::warning("[ApiGuard] The API key ID#{$this->apiKey->id} has reached the limit of {$keyLimit} in the following route: " . Route::currentRouteAction());
                             return $response->setStatusCode(429)->withError('You have reached the limit for using this API.', 'GEN-TOO-MANY-REQUESTS');
                         }
                     }
                 }
             }
         }
         // Then the overall method limits
         if (!empty($limits['method'])) {
             $methodLimit = !empty($limits['method']['limit']) ? $limits['method']['limit'] : 0;
             if ($methodLimit == 0 || is_integer($methodLimit) == false) {
                 Log::warning("[ApiGuard] You defined a method limit to the " . Route::currentRouteAction() . " route but you did not set a valid number for the limit variable.");
             } else {
                 if ($this->apiKey != null && $this->apiKey->ignore_limits == true) {
                     // then we skip this
                 } else {
                     $methodIncrement = !empty($limits['method']['increment']) ? $limits['method']['increment'] : config('apiguard.keyLimitIncrement', '1 hour');
                     $methodIncrementTime = strtotime('-' . $methodIncrement);
                     if ($methodIncrementTime == false) {
                         Log::warning("[ApiGuard] You have specified an invalid method increment time. This value can be any value accepted by PHP's strtotime() method");
                     } else {
                         // Count the number of requests for this method
                         $apiLogCount = $apiLog->countMethodRequests(Route::currentRouteAction(), $request->getMethod(), $methodIncrementTime);
                         if ($apiLogCount >= $methodLimit) {
                             Log::warning("[ApiGuard] The API has reached the method limit of {$methodLimit} in the following route: " . Route::currentRouteAction());
                             return $response->setStatusCode(429)->withError('The limit for using this API method has been reached', 'GEN-TOO-MANY-REQUESTS');
                         }
                     }
                 }
             }
         }
     }
     // End of cheking limits
     if (config('apiguard.logging', true)) {
         // Default to log requests from this action
         $logged = true;
         if (isset($this->apiMethods[$method]['logged']) && $this->apiMethods[$method]['logged'] === false) {
             $logged = false;
         }
         if ($logged) {
             // Log this API request
             $this->apiLog = App::make(config('apiguard.models.apiLog', 'Chrisbjr\\ApiGuard\\Models\\ApiLog'));
             if (isset($this->apiKey)) {
                 $this->apiLog->api_key_id = $this->apiKey->id;
             }
             $this->apiLog->create(['api_key_id' => isset($this->apiKey) ? $this->apiKey->id : null, 'route' => Route::currentRouteAction(), 'method' => $request->getMethod(), 'params' => http_build_query(Input::all()), 'ip_address' => $request->getClientIp()]);
         }
     }
     return $next($request);
 }