initial
This commit is contained in:
@@ -0,0 +1,200 @@
|
||||
<?php
|
||||
|
||||
namespace Gravity_Forms\Gravity_Forms_RECAPTCHA;
|
||||
|
||||
use GFCache, GFAddOn;
|
||||
|
||||
/**
|
||||
* Refresh token lock.
|
||||
*
|
||||
* Hosts the logic required to prevent repeated refresh token requests.
|
||||
*
|
||||
* @since 1.8.0
|
||||
*/
|
||||
class Refresh_Lock_Handler {
|
||||
|
||||
/**
|
||||
* How many seconds until the rate limiting cache lock is cleared.
|
||||
*
|
||||
* @since 1.8.0
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
const RATE_LIMIT_CACHE_EXPIRATION_SECONDS = MINUTE_IN_SECONDS;
|
||||
|
||||
/**
|
||||
* How many failed refresh requests until the refresh is locked becayse of rate limiting.
|
||||
*
|
||||
* @since 1.8.0
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
const RATE_LIMIT_FAILED_REQUEST_THRESHOLD = 3;
|
||||
|
||||
/**
|
||||
* How many seconds until the refresh in progress cache lock is cleared.
|
||||
*
|
||||
* @since 1.8.0
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
const REFRESH_IN_PROGRESS_EXPIRATION_SECONDS = MINUTE_IN_SECONDS;
|
||||
|
||||
/**
|
||||
* Failed request count option key.
|
||||
*
|
||||
* @since 1.8.0
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $failed_requests_count_key = '';
|
||||
|
||||
/**
|
||||
* The refresh in progress cache key.
|
||||
*
|
||||
* @since 1.8.0
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $refresh_in_progress_lock_key = '';
|
||||
|
||||
/**
|
||||
* The rate limiting cache key.
|
||||
*
|
||||
* @since 1.8.0
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $rate_limit_lock_key = '';
|
||||
|
||||
/**
|
||||
* The reason why the refreshing could be locked.
|
||||
*
|
||||
* @since 1.8.0
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $refresh_lock_reason = '';
|
||||
|
||||
/**
|
||||
* An instance of the add-on.
|
||||
*
|
||||
* @since 1.8.0
|
||||
*
|
||||
* @var GFAddOn
|
||||
*/
|
||||
protected $addon;
|
||||
|
||||
/**
|
||||
* Handler constructor.
|
||||
*
|
||||
* @since 1.8.0
|
||||
*
|
||||
* @param GFAddOn $addon The add-on the handler is being initialized for.
|
||||
*/
|
||||
public function __construct( $addon ) {
|
||||
$this->addon = $addon;
|
||||
$slug = $addon->get_slug();
|
||||
$this->failed_requests_count_key = $slug . '_failed_refresh_token_requests_count';
|
||||
$this->refresh_in_progress_lock_key = $slug . '_refresh_lock';
|
||||
$this->rate_limit_lock_key = $slug . '_rate_limit';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the rate limit cache key is set, and sets the lock reason if locked.
|
||||
*
|
||||
* After consecutive failed requests, a cache key is set to prevent more failed requests.
|
||||
*
|
||||
* @sicne 1.8.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_rate_limited() {
|
||||
$rate_limited = GFCache::get( $this->rate_limit_lock_key, $found );
|
||||
if ( $found && $rate_limited ) {
|
||||
$this->refresh_lock_reason = 'Refresh token request rate limit reached.';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the threshold for failed refresh requests has been reached, sets the cache key if so.
|
||||
*
|
||||
* @since 1.8.0
|
||||
*/
|
||||
public function increment_rate_limit() {
|
||||
$failed_requests_count = intval( get_option( $this->failed_requests_count_key ) );
|
||||
if ( $failed_requests_count >= self::RATE_LIMIT_FAILED_REQUEST_THRESHOLD ) {
|
||||
$this->addon->log_debug( __METHOD__ . '(): Rate limit threshold reached, setting rate limit lock.' );
|
||||
GFCache::set( $this->rate_limit_lock_key, true, true, self::RATE_LIMIT_CACHE_EXPIRATION_SECONDS );
|
||||
update_option( $this->failed_requests_count_key, 0 );
|
||||
} else {
|
||||
$this->addon->log_debug( __METHOD__ . '(): Increasing failed requests count, current count: ' . $failed_requests_count );
|
||||
update_option( $this->failed_requests_count_key, $failed_requests_count + 1 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there is a request already being made for refreshing the token.
|
||||
*
|
||||
* @since 1.8.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_locked() {
|
||||
$locked = GFCache::get( $this->refresh_in_progress_lock_key, $found );
|
||||
if ( $found && $locked ) {
|
||||
$this->refresh_lock_reason = 'Token Refresh is already in progress.';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the refresh in progress cache lock.
|
||||
*
|
||||
* @since 1.8.0
|
||||
*/
|
||||
public function lock() {
|
||||
GFCache::set( $this->refresh_in_progress_lock_key, true, true, self::REFRESH_IN_PROGRESS_EXPIRATION_SECONDS );
|
||||
$this->addon->log_debug( __METHOD__ . '(): Refresh in progress lock has been set.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the rate limit lock.
|
||||
*
|
||||
* @since 1.8.0
|
||||
*/
|
||||
public function reset_rate_limit() {
|
||||
GFCache::delete( $this->rate_limit_lock_key );
|
||||
update_option( $this->failed_requests_count_key, 0 );
|
||||
$this->addon->log_debug( __METHOD__ . '(): Rate limit lock cleared.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the refresh in progress lock.
|
||||
*
|
||||
* @since 1.8.0
|
||||
*/
|
||||
public function release_lock() {
|
||||
GFCache::delete( $this->refresh_in_progress_lock_key );
|
||||
$this->addon->log_debug( __METHOD__ . '(): Refresh in progress lock cleared.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the token can be refreshed after making sure no locks are in place.
|
||||
*
|
||||
* @since 1.8.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function can_refresh_token() {
|
||||
return $this->is_rate_limited() === false && $this->is_locked() === false;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user