diff --git a/src/Exceptions/FailTooManyRequestsException.php b/src/Exceptions/FailTooManyRequestsException.php new file mode 100644 index 0000000..08463a3 --- /dev/null +++ b/src/Exceptions/FailTooManyRequestsException.php @@ -0,0 +1,20 @@ +setData(array( 'key' => $key ))->renderString(lang('Rest.textRestApiKeyTimeLimit'))); + } + + public static function forInvalidAttemptsLimit(string $ip, string $date) + { + $parser = \Config\Services::parser(); + return new self($parser->setData(array( 'ip' => $ip, 'date' => $date ))->renderString(lang('Rest.textRestInvalidAttemptsLimit'))); + } +} diff --git a/src/Exceptions/UnauthorizedException.php b/src/Exceptions/UnauthorizedException.php index dade836..fc14c1e 100644 --- a/src/Exceptions/UnauthorizedException.php +++ b/src/Exceptions/UnauthorizedException.php @@ -44,11 +44,6 @@ public static function forIpDenied() return new self(lang('Rest.ipDenied')); } - public static function forApiKeyLimit() - { - return new self(lang('Rest.textRestApiKeyTimeLimit')); - } - public static function forApiKeyPermissions() { return new self(lang('Rest.textRestApiKeyPermissions')); diff --git a/src/Interfaces/FailTooManyRequestsInterface.php b/src/Interfaces/FailTooManyRequestsInterface.php new file mode 100644 index 0000000..392c323 --- /dev/null +++ b/src/Interfaces/FailTooManyRequestsInterface.php @@ -0,0 +1,10 @@ + 'Unsupported protocol', - 'textRestInvalidApiKey' => 'Invalid API key {key}', + 'textRestInvalidApiKey' => 'Invalid API key \'{key}\'', 'textRestInvalidCredentials' => 'Invalid credentials', 'textRestInvalidToken' => 'Invalid Token', 'tokenExpired' => 'The token has expired', 'tokenUnauthorized' => 'Invalid Auth token', 'ipDenied' => 'IP denied', 'textUnauthorized' => 'Unauthorized', - 'textRestApiKeyTimeLimit' => 'This API key has reached the time limit for this method', + 'textRestApiKeyTimeLimit' => 'This API key \'{key}\' has reached the time limit for this method', + 'textRestInvalidAttemptsLimit' => 'This IP \'{ip}\' has reached the maximum of invalid requests, it will have access from: \'{date}\'', 'textRestApiKeyPermissions' => 'This API key does not have enough permissions', 'textRestIpAddressTimeLimit' => 'This IP Address has reached the time limit for this method', 'textRestApiKeyUnauthorized' => 'This API key does not have access to the requested controller', 'textInvalidUserClassConfiguration' => 'Invalid user class configuration, extends( \Daycry\RestServer\Libraries\User\UserAbstract )', 'textRestAjaxOnly' => 'Only AJAX requests are allowed', - 'textInvalidMethodParams' => 'Invalid params for this method: {param}' + 'textInvalidMethodParams' => 'Invalid params for this method: \'{param}\'' ]; /* diff --git a/src/RestServer.php b/src/RestServer.php index 95cf72b..f76ff14 100644 --- a/src/RestServer.php +++ b/src/RestServer.php @@ -10,6 +10,7 @@ use Daycry\RestServer\Exceptions\UnauthorizedException; use Daycry\RestServer\Exceptions\ValidationException; use Daycry\RestServer\Exceptions\ForbiddenException; +use Daycry\RestServer\Exceptions\FailTooManyRequestsException; use Daycry\RestServer\Libraries\User\UserAbstract; @@ -563,7 +564,7 @@ private function _checkAttempt() { $attemptModel->delete( $attempt->id, true ); }else{ - $return = false; + $return = date('Y-m-d H:i:s', $attempt->hour_started + $this->_restConfig->restTimeBlocked ); } } @@ -724,10 +725,11 @@ public function _remap($method, ...$params) throw ForbiddenException::forUnsupportedProtocol(); } - if( $this->_restConfig->restEnableInvalidAttempts === true && !$this->_checkAttempt()) + $attempt = $this->_checkAttempt(); + if( $this->_restConfig->restEnableInvalidAttempts === true && $attempt !== true) { $this->authorized = false; - throw UnauthorizedException::forApiKeyLimit(); + throw FailTooManyRequestsException::forInvalidAttemptsLimit( $this->request->getIPAddress(), $attempt ); } if ($this->request->isAJAX() === false && $this->_restConfig->restAjaxOnly) { @@ -784,7 +786,7 @@ public function _remap($method, ...$params) // Check the limit if ($this->_restConfig->restEnableLimits && $this->_checkLimit() === false) { $this->authorized = false; - throw UnauthorizedException::forApiKeyLimit(); + throw FailTooManyRequestsException::forApiKeyLimit( $this->key ); } // If no level is set use 0, they probably aren't using permissions @@ -808,6 +810,8 @@ public function _remap($method, ...$params) return \call_user_func_array([ $this, $this->router->methodName() ], $params); } catch (\Daycry\RestServer\Interfaces\UnauthorizedInterface $ex) { return $this->failUnauthorized($ex->getMessage(), $ex->getCode()); + } catch (\Daycry\RestServer\Interfaces\FailTooManyRequestsInterface $ex) { + return $this->failTooManyRequests($ex->getMessage(), $ex->getCode()); } catch (\Daycry\RestServer\Interfaces\ForbiddenInterface $ex) { return $this->failForbidden($ex->getMessage(), $ex->getCode()); } catch (\Daycry\RestServer\Interfaces\ValidationInterface $ex) { @@ -899,9 +903,12 @@ public function __destruct() $attemptModel->save($attempt); }else{ - $attempt->attempts = $attempt->attempts + 1; - $attempt->hour_started = time(); - $attemptModel->save($attempt); + if( $attempt->attempts < $this->_restConfig->restMaxAttempts ) + { + $attempt->attempts = $attempt->attempts + 1; + $attempt->hour_started = time(); + $attemptModel->save($attempt); + } } } }