Файл: gapps/vendor/cartalyst/sentinel/src/Throttling/IlluminateThrottleRepository.php
Строк: 390
<?php
/**
* Part of the Sentinel package.
*
* NOTICE OF LICENSE
*
* Licensed under the 3-clause BSD License.
*
* This source file is subject to the 3-clause BSD License that is
* bundled with this package in the LICENSE file.
*
* @package Sentinel
* @version 2.0.15
* @author Cartalyst LLC
* @license BSD License (3-clause)
* @copyright (c) 2011-2017, Cartalyst LLC
* @link http://cartalyst.com
*/
namespace CartalystSentinelThrottling;
use CarbonCarbon;
use CartalystSentinelUsersUserInterface;
use CartalystSupportTraitsRepositoryTrait;
class IlluminateThrottleRepository implements ThrottleRepositoryInterface
{
use RepositoryTrait;
/**
* The interval which failed logins are checked, to prevent brute force.
*
* @var int
*/
protected $globalInterval = 900;
/**
* The global thresholds configuration array.
*
* If an array is set, the key is the number of failed login attempts
* and the value is the delay in seconds before another login can
* occur.
*
* If an integer is set, it represents the number of attempts
* before throttling locks out in the current interval.
*
* @var int|array
*/
protected $globalThresholds = [
10 => 1,
20 => 2,
30 => 4,
40 => 8,
50 => 16,
60 => 32,
];
/**
* Cached global throttles collection within the interval.
*
* @var IlluminateDatabaseEloquentCollection
*/
protected $globalThrottles;
/**
* The interval at which point one IP address' failed logins are checked.
*
* @var int
*/
protected $ipInterval = 900;
/**
* Works identical to global thresholds, except specific to an IP address.
*
* @var int|array
*/
protected $ipThresholds = 5;
/**
* The cached IP address throttle collections within the interval.
*
* @var array
*/
protected $ipThrottles = [];
/**
* The interval at which point failed logins for one user are checked.
*
* @var int
*/
protected $userInterval = 900;
/**
* Works identical to global and IP address thresholds, regarding a user.
*
* @var int|array
*/
protected $userThresholds = 5;
/**
* The cached user throttle collections within the interval.
*
* @var IlluminateDatabaseEloquentCollection
*/
protected $userThrottles = [];
/**
* Create a new Illuminate throttle repository.
*
* @param string $model
* @param int $globalInterval
* @param int|array $globalThresholds
* @param int $ipInterval
* @param int|array $ipThresholds
* @param int $userInterval
* @param int|array $userThresholds
* @return void
*/
public function __construct(
$model = 'CartalystSentinelThrottlingEloquentThrottle',
$globalInterval = null,
$globalThresholds = null,
$ipInterval = null,
$ipThresholds = null,
$userInterval = null,
$userThresholds = null
) {
$this->model = $model;
if (isset($globalInterval)) {
$this->setGlobalInterval($globalInterval);
}
if (isset($globalThresholds)) {
$this->setGlobalThresholds($globalThresholds);
}
if (isset($ipInterval)) {
$this->setIpInterval($ipInterval);
}
if (isset($ipThresholds)) {
$this->setIpThresholds($ipThresholds);
}
if (isset($userInterval)) {
$this->setUserInterval($userInterval);
}
if (isset($userThresholds)) {
$this->setUserThresholds($userThresholds);
}
}
/**
* {@inheritDoc}
*/
public function globalDelay()
{
return $this->delay('global');
}
/**
* {@inheritDoc}
*/
public function ipDelay($ipAddress)
{
return $this->delay('ip', $ipAddress);
}
/**
* {@inheritDoc}
*/
public function userDelay(UserInterface $user)
{
return $this->delay('user', $user);
}
/**
* {@inheritDoc}
*/
public function log($ipAddress = null, UserInterface $user = null)
{
$global = $this->createModel();
$global->fill([
'type' => 'global',
]);
$global->save();
if ($ipAddress !== null) {
$ipAddressThrottle = $this->createModel();
$ipAddressThrottle->fill([
'type' => 'ip',
'ip' => $ipAddress,
]);
$ipAddressThrottle->save();
}
if ($user !== null) {
$userThrottle = $this->createModel();
$userThrottle->fill([
'type' => 'user',
]);
$userThrottle->user_id = $user->getUserId();
$userThrottle->save();
}
}
/**
* Returns the global interval.
*
* @return int
*/
public function getGlobalInterval()
{
return $this->globalInterval;
}
/**
* Sets the global interval.
*
* @param int $globalInterval
* @return void
*/
public function setGlobalInterval($globalInterval)
{
$this->globalInterval = (int) $globalInterval;
}
/**
* Returns the global thresholds.
*
* @return int|array
*/
public function getGlobalThresholds()
{
return $this->globalThresholds;
}
/**
* Sets the global thresholds.
*
* @param int|array $globalThresholds
* @return void
*/
public function setGlobalThresholds($globalThresholds)
{
$this->globalThresholds = is_array($globalThresholds) ? $globalThresholds : (int) $globalThresholds;
}
/**
* Returns the IP address interval.
*
* @return int
*/
public function getIpInterval()
{
return $this->ipInterval;
}
/**
* Sets the IP address interval.
*
* @param int $ipInterval
* @return void
*/
public function setIpInterval($ipInterval)
{
$this->ipInterval = (int) $ipInterval;
}
/**
* Returns the IP address thresholds.
*
* @return int|array
*/
public function getIpThresholds()
{
return $this->ipThresholds;
}
/**
* Sets the IP address thresholds.
*
* @param int|array $ipThresholds
* @return void
*/
public function setIpThresholds($ipThresholds)
{
$this->ipThresholds = is_array($ipThresholds) ? $ipThresholds : (int) $ipThresholds;
}
/**
* Returns the user interval.
*
* @return int
*/
public function getUserInterval()
{
return $this->userInterval;
}
/**
* Sets the user interval.
*
* @param int $userInterval
* @return void
*/
public function setUserInterval($userInterval)
{
$this->userInterval = (int) $userInterval;
}
/**
* Returns the user thresholds.
*
* @return int|array
*/
public function getUserThresholds()
{
return $this->userThresholds;
}
/**
* Sets the user thresholds.
*
* @param int|array $userThresholds
* @return void
*/
public function setUserThresholds($userThresholds)
{
$this->userThresholds = is_array($userThresholds) ? $userThresholds : (int) $userThresholds;
}
/**
* Returns a delay for the given type.
*
* @param string $type
* @param mixed $argument
* @return int
*/
protected function delay($type, $argument = null)
{
// Based on the given type, we will generate method and property names
$method = 'get'.studly_case($type).'Throttles';
$thresholds = $type.'Thresholds';
$throttles = $this->{$method}($argument);
if (! $throttles->count()) {
return 0;
}
if (is_array($this->$thresholds)) {
// Great, now we compare our delay against the most recent attempt
$last = $throttles->last();
foreach (array_reverse($this->$thresholds, true) as $attempts => $delay) {
if ($throttles->count() <= $attempts) {
continue;
}
if ($last->created_at->diffInSeconds() < $delay) {
return $this->secondsToFree($last, $delay);
}
}
} elseif ($throttles->count() > $this->$thresholds) {
$interval = $type.'Interval';
$first = $throttles->first();
return $this->secondsToFree($first, $this->{$interval});
}
return 0;
}
/**
* Returns the global throttles collection.
*
* @return IlluminateDatabaseEloquentCollection
*/
protected function getGlobalThrottles()
{
if ($this->globalThrottles === null) {
$this->globalThrottles = $this->loadGlobalThrottles();
}
return $this->globalThrottles;
}
/**
* Loads and returns the global throttles collection.
*
* @return IlluminateDatabaseEloquentCollection
*/
protected function loadGlobalThrottles()
{
$interval = Carbon::now()
->subSeconds($this->globalInterval);
return $this->createModel()
->newQuery()
->where('type', 'global')
->where('created_at', '>', $interval)
->get();
}
/**
* Returns the IP address throttles collection.
*
* @param string $ipAddress
* @return IlluminateDatabaseEloquentCollection
*/
protected function getIpThrottles($ipAddress)
{
if (! array_key_exists($ipAddress, $this->ipThrottles)) {
$this->ipThrottles[$ipAddress] = $this->loadIpThrottles($ipAddress);
}
return $this->ipThrottles[$ipAddress];
}
/**
* Loads and returns the IP address throttles collection.
*
* @param string $ipAddress
* @return IlluminateDatabaseEloquentCollection
*/
protected function loadIpThrottles($ipAddress)
{
$interval = Carbon::now()
->subSeconds($this->ipInterval);
return $this
->createModel()
->newQuery()
->where('type', 'ip')
->where('ip', $ipAddress)
->where('created_at', '>', $interval)
->get();
}
/**
* Returns the user throttles collection.
*
* @param CartalystSentinelUsersUserInterface $user
* @return IlluminateDatabaseEloquentCollection
*/
protected function getUserThrottles(UserInterface $user)
{
$key = $user->getUserId();
if (! array_key_exists($key, $this->userThrottles)) {
$this->userThrottles[$key] = $this->loadUserThrottles($user);
}
return $this->userThrottles[$key];
}
/**
* Loads and returns the user throttles collection.
*
* @param CartalystSentinelUsersUserInterface $user
* @return IlluminateDatabaseEloquentCollection
*/
protected function loadUserThrottles(UserInterface $user)
{
$interval = Carbon::now()
->subSeconds($this->userInterval);
return $this
->createModel()
->newQuery()
->where('type', 'user')
->where('user_id', $user->getUserId())
->where('created_at', '>', $interval)
->get();
}
/**
* Returns the seconds to free based on the given throttle and
* the presented delay in seconds, by comparing it to now.
*
* @param CartalystSentinelThrottlingEloquentThrottle $throttle
* @param int $interval
* @return int
*/
protected function secondsToFree(EloquentThrottle $throttle, $interval)
{
return $throttle->created_at->addSeconds($interval)->diffInSeconds();
}
}