diff --git a/CHANGELOG.md b/CHANGELOG.md index fae3161..b78370c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [0.24.0] - 2022-07-08 + +### Added +- Add a `configs` attribute to Bouncer class + ## [0.23.0] - 2022-07-07 ### Added diff --git a/src/AbstractBounce.php b/src/AbstractBounce.php index ccff8c1..1b187fa 100644 --- a/src/AbstractBounce.php +++ b/src/AbstractBounce.php @@ -117,44 +117,37 @@ protected function initLoggerHelper(string $logDirectoryPath, string $loggerName /** * Handle X-Forwarded-For HTTP header to retrieve the IP to bounce * - * @param $ip - * @return false|mixed + * @param string $ip + * @param array $configs + * @return string */ - protected function handleForwardedFor($ip) + protected function handleForwardedFor(string $ip, array $configs): string { - if (empty($this->settings['forced_test_forwarded_ip'])) { + $forwardedIp = null; + if (empty($configs['forced_test_forwarded_ip'])) { $XForwardedForHeader = $this->getHttpRequestHeader('X-Forwarded-For'); if (null !== $XForwardedForHeader) { $ipList = array_map('trim', array_values(array_filter(explode(',', $XForwardedForHeader)))); $forwardedIp = end($ipList); - if ($this->shouldTrustXforwardedFor($ip)) { - $ip = $forwardedIp; - } else { - $this->logger->warning('', [ - 'type' => 'NON_AUTHORIZED_X_FORWARDED_FOR_USAGE', - 'original_ip' => $ip, - 'x_forwarded_for_ip' => $forwardedIp, - ]); - } } - } else if ($this->settings['forced_test_forwarded_ip'] === Constants::X_FORWARDED_DISABLED) { + } else if ($configs['forced_test_forwarded_ip'] === Constants::X_FORWARDED_DISABLED) { $this->logger->debug('', [ 'type' => 'DISABLED_X_FORWARDED_FOR_USAGE', 'original_ip' => $ip, ]); } else { - $forwardedIp = $this->settings['forced_test_forwarded_ip']; - if ($this->shouldTrustXforwardedFor($ip)) { - $ip = $forwardedIp; - } else { - $this->logger->warning('', [ - 'type' => 'NON_AUTHORIZED_TEST_X_FORWARDED_FOR_USAGE', - 'original_ip' => $ip, - 'x_forwarded_for_ip_for_test' => $forwardedIp, - ]); - } + $forwardedIp = (string) $configs['forced_test_forwarded_ip']; } + if (is_string($forwardedIp) && $this->shouldTrustXforwardedFor($ip)) { + $ip = $forwardedIp; + } else { + $this->logger->warning('', [ + 'type' => 'NON_AUTHORIZED_X_FORWARDED_FOR_USAGE', + 'original_ip' => $ip, + 'x_forwarded_for_ip' => is_string($forwardedIp) ? $forwardedIp : 'type not as expected', + ]); + } return $ip; } @@ -171,9 +164,10 @@ protected function bounceCurrentIp(): void if (!$this->bouncer) { throw new BouncerException('Bouncer must be instantiated to bounce an IP.'); } + $configs = $this->bouncer->getConfigs(); // Retrieve the current IP (even if it is a proxy IP) or a testing IP - $ip = !empty($this->settings['forced_test_ip']) ? $this->settings['forced_test_ip'] : $this->getRemoteIp(); - $ip = $this->handleForwardedFor($ip); + $ip = !empty($configs['forced_test_ip']) ? $configs['forced_test_ip'] : $this->getRemoteIp(); + $ip = $this->handleForwardedFor($ip, $configs); $remediation = $this->bouncer->getRemediationForIp($ip); $this->handleRemediation($remediation, $ip); } catch (Exception $e) { diff --git a/src/Bouncer.php b/src/Bouncer.php index c388096..537cff5 100644 --- a/src/Bouncer.php +++ b/src/Bouncer.php @@ -37,11 +37,15 @@ class Bouncer /** @var int */ private $maxRemediationLevelIndex = 0; + /** @var array */ + private $configs = []; + public function __construct( TagAwareAdapterInterface $cacheAdapter = null, - LoggerInterface $logger = null, - ApiCache $apiCache = null - ) { + LoggerInterface $logger = null, + ApiCache $apiCache = null + ) + { if (!$logger) { $logger = new Logger('null'); $logger->pushHandler(new NullHandler()); @@ -50,6 +54,16 @@ public function __construct( $this->apiCache = $apiCache ?: new ApiCache($logger, new ApiClient($logger), $cacheAdapter); } + /** + * Retrieve Bouncer configurations + * + * @return array + */ + public function getConfigs(): array + { + return $this->configs; + } + /** * Configure this instance. * @@ -59,33 +73,33 @@ public function __construct( */ public function configure(array $config): void { - // Process input configuration. + // Process and validate input configuration. $configuration = new Configuration(); $processor = new Processor(); - $finalConfig = $processor->processConfiguration($configuration, [$config]); + $this->configs = $processor->processConfiguration($configuration, [$config]); /** @var int */ $index = array_search( - $finalConfig['max_remediation_level'], + $this->configs['max_remediation_level'], Constants::ORDERED_REMEDIATIONS ); $this->maxRemediationLevelIndex = $index; $cacheDurations = [ - 'clean_ip_cache_duration' => $finalConfig['clean_ip_cache_duration'], - 'bad_ip_cache_duration' => $finalConfig['bad_ip_cache_duration'], - 'captcha_cache_duration' => $finalConfig['captcha_cache_duration'], - 'geolocation_cache_duration' => $finalConfig['geolocation_cache_duration'], + 'clean_ip_cache_duration' => $this->configs['clean_ip_cache_duration'], + 'bad_ip_cache_duration' => $this->configs['bad_ip_cache_duration'], + 'captcha_cache_duration' => $this->configs['captcha_cache_duration'], + 'geolocation_cache_duration' => $this->configs['geolocation_cache_duration'], ]; // Configure Api Cache. $this->apiCache->configure( - $finalConfig['stream_mode'], - $finalConfig['api_url'], - $finalConfig['api_timeout'], - $finalConfig['api_user_agent'], - $finalConfig['api_key'], + $this->configs['stream_mode'], + $this->configs['api_url'], + $this->configs['api_timeout'], + $this->configs['api_user_agent'], + $this->configs['api_key'], $cacheDurations, - $finalConfig['fallback_remediation'], - $finalConfig['geolocation'] + $this->configs['fallback_remediation'], + $this->configs['geolocation'] ); } @@ -115,7 +129,7 @@ private function capRemediationLevel(string $remediation): string * * @return string the remediation to apply (ex: 'ban', 'captcha', 'bypass') * - * @throws InvalidArgumentException + * @throws InvalidArgumentException|\Psr\Cache\CacheException */ public function getRemediationForIp(string $ip): string { @@ -154,11 +168,12 @@ public static function getAccessForbiddenHtmlTemplate(array $config): string * The input $config should match the TemplateConfiguration input format. */ public static function getCaptchaHtmlTemplate( - bool $error, + bool $error, string $captchaImageSrc, string $captchaResolutionFormUrl, - array $config - ): string { + array $config + ): string + { // Process template configuration. $configuration = new TemplateConfiguration(); $processor = new Processor(); @@ -176,7 +191,7 @@ public static function getCaptchaHtmlTemplate( * * @return array "count": number of decisions added, "errors": decisions not added * - * @throws InvalidArgumentException + * @throws InvalidArgumentException|\Psr\Cache\CacheException */ public function warmBlocklistCacheUp(): array { @@ -189,7 +204,7 @@ public function warmBlocklistCacheUp(): array * * @return array Number of deleted and new decisions, and errors when processing decisions * - * @throws InvalidArgumentException + * @throws InvalidArgumentException|\Psr\Cache\CacheException */ public function refreshBlocklistCache(): array { diff --git a/src/Constants.php b/src/Constants.php index 5326d32..ff90a88 100644 --- a/src/Constants.php +++ b/src/Constants.php @@ -20,7 +20,7 @@ class Constants public const DEFAULT_LAPI_URL = 'http://localhost:8080'; /** @var string The last version of this library */ - public const VERSION = 'v0.23.0'; + public const VERSION = 'v0.24.0'; /** @var string The user agent used to send request to LAPI */ public const BASE_USER_AGENT = 'PHP CrowdSec Bouncer/' . self::VERSION; diff --git a/src/StandaloneBounce.php b/src/StandaloneBounce.php index 9750ec5..6aa0e91 100644 --- a/src/StandaloneBounce.php +++ b/src/StandaloneBounce.php @@ -132,6 +132,7 @@ public function getBouncerInstance(array $settings, bool $forceReload = false): if ($this->bouncer && !$forceReload) { return $this->bouncer; } + $this->settings = array_merge($this->settings, $settings); $bouncingLevel = $this->getStringSettings('bouncing_level'); $apiUserAgent = 'Standalone CrowdSec PHP Bouncer/' . Constants::VERSION; $apiTimeout = $this->getIntegerSettings('api_timeout');