new: [flood protection] behaviour added
simple expiration system to allow flood protections to be added to any functionalitycli-modification-summary
parent
d1cdbda972
commit
e6643365d2
|
@ -41,6 +41,7 @@ class AppController extends Controller
|
|||
public $restResponsePayload = null;
|
||||
public $user = null;
|
||||
public $breadcrumb = [];
|
||||
public $request_ip = null;
|
||||
|
||||
/**
|
||||
* Initialization hook method.
|
||||
|
@ -83,6 +84,7 @@ class AppController extends Controller
|
|||
Configure::write('DebugKit.forceEnable', true);
|
||||
}
|
||||
$this->loadComponent('CustomPagination');
|
||||
$this->loadComponent('FloodProtection');
|
||||
/*
|
||||
* Enable the following component for recommended CakePHP form protection settings.
|
||||
* see https://book.cakephp.org/4/en/controllers/components/form-protection.html
|
||||
|
@ -92,6 +94,7 @@ class AppController extends Controller
|
|||
|
||||
public function beforeFilter(EventInterface $event)
|
||||
{
|
||||
//$this->request_ip = Configure::read('')
|
||||
$this->loadModel('Users');
|
||||
$this->Users->checkForNewInstance();
|
||||
$this->authApiUser();
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller\Component;
|
||||
|
||||
use Cake\Controller\Component;
|
||||
use App\Model\Entity\User;
|
||||
use App\Http\Exception\TooManyRequestsException;
|
||||
use Cake\ORM\TableRegistry;
|
||||
use Cake\Core\Configure;
|
||||
use Cake\Core\Configure\Engine\PhpConfig;
|
||||
|
||||
class FloodProtectionComponent extends Component
|
||||
{
|
||||
private $remote_ip = null;
|
||||
private $FloodProtections = null;
|
||||
|
||||
public function initialize(array $config): void
|
||||
{
|
||||
$ip_source = Configure::check('security.logging.ip_source') ? Configure::read('security.logging.ip_source') : 'REMOTE_ADDR';
|
||||
$this->remote_ip = $_SERVER[$ip_source];
|
||||
$temp = explode(PHP_EOL, $_SERVER[$ip_source]);
|
||||
if (count($temp) > 1) {
|
||||
$this->remote_ip = $temp[0];
|
||||
}
|
||||
$this->FloodProtections = TableRegistry::getTableLocator()->get('FloodProtections');
|
||||
}
|
||||
|
||||
public function check(string $action, int $limit = 5, int $expiration_time = 300): bool
|
||||
{
|
||||
$results = $this->FloodProtections->find('all')->where(['request_action' => $action, 'remote_ip' => $this->remote_ip, 'expiration' > time()])->toList();
|
||||
if (count($results) >= $limit) {
|
||||
throw new TooManyRequestsException(__('Too many {0} requests have been issued ({1} requests allowed ever {2} seconds)', [$action, $limit, $expiration_time]));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function set(string $action, int $expiration_time = 300): bool
|
||||
{
|
||||
$entry = $this->FloodProtections->newEmptyEntity();
|
||||
$entry->expiration = time() + $expiration_time;
|
||||
$entry->remote_ip = $this->remote_ip;
|
||||
$entry->request_action = $action;
|
||||
return (bool)$this->FloodProtections->save($entry);
|
||||
|
||||
}
|
||||
|
||||
public function checkAndSet(string $action, int $limit = 5, int $expiration_time = 300): bool
|
||||
{
|
||||
$result = $this->check($action, $limit, $expiration_time);
|
||||
$this->set($action, $expiration_time);
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function cleanup(): void
|
||||
{
|
||||
$this->FloodProtection->deleteAll(['expiration' < time()]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace App\Model\Table;
|
||||
|
||||
use App\Model\Table\AppTable;
|
||||
use Cake\ORM\Table;
|
||||
use Cake\Validation\Validator;
|
||||
|
||||
class FloodProtectionsTable extends AppTable
|
||||
{
|
||||
public function initialize(array $config): void
|
||||
{
|
||||
parent::initialize($config);
|
||||
$this->setDisplayField('request_ip');
|
||||
}
|
||||
|
||||
public function validationDefault(Validator $validator): Validator
|
||||
{
|
||||
return $validator;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue