Skip to content

Commit cf99cb3

Browse files
feat(*): Update bouncer configurations. Replace live_mode by stream_mode everywhere
1 parent 5405819 commit cf99cb3

13 files changed

+140
-38
lines changed

docs/api/ApiCache.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ The cache mecanism to store every decisions from LAPI/CAPI. Symfony Cache compon
7575
**Description**
7676

7777
```php
78-
public configure (bool $liveMode, string $apiUrl, int $timeout, string $userAgent, string $apiKey, int $cacheExpirationForCleanIp, int $cacheExpirationForBadIp, string $fallbackRemediation)
78+
public configure (bool $streamMode, string $apiUrl, int $timeout, string $userAgent, string $apiKey, int
79+
$cacheExpirationForCleanIp, int $cacheExpirationForBadIp, string $fallbackRemediation)
7980
```
8081

8182
Configure this instance.
@@ -84,8 +85,8 @@ Configure this instance.
8485

8586
**Parameters**
8687

87-
* `(bool) $liveMode`
88-
: If we use the live mode (else we use the stream mode)
88+
* `(bool) $streamMode`
89+
: If we use the stream mode (else we use the live mode)
8990
* `(string) $apiUrl`
9091
: The URL of the LAPI
9192
* `(int) $timeout`

docs/configuration-reference.md

Lines changed: 73 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Full configuration reference
22

3-
```bash
3+
```php
44
$config = [
55
// Required. The bouncer api key to access LAPI or CAPI.
66
'api_key'=> 'YOUR_BOUNCER_API_KEY',
@@ -11,25 +11,89 @@
1111
// Optional. HTTP user agent used to call CAPI or LAPI. Default to this library name/current version.
1212
'api_user_agent'=> 'CrowdSec PHP Library/x.x.x',
1313

14-
// Optional. In seconds. The timeout when calling CAPI/LAPI. Defaults to 2 sec.
15-
'api_timeout'=> 2,
14+
// Optional. In seconds. The timeout when calling CAPI/LAPI. Defaults to 1 sec.
15+
'api_timeout'=> 1,
16+
17+
// Optional. Select from 'bouncing_disabled', 'normal_bouncing' or 'flex_bouncing'. Default to 'normal_bouncing'
18+
'bouncing_level' => 'normal_bouncing',
19+
20+
// Optional. Absolute path to store log files.
21+
'log_directory_path' => __DIR__.'/.logs',
22+
23+
// Optional. Select from 'phpfs' (File system cache), 'redis' or 'memcached'. Default to 'phpcs'
24+
'cache_system' => 'phpfs',
25+
26+
// Optional. Will be used only if you choose File system as cache_system
27+
'fs_cache_path' => __DIR__.'/.cache',
28+
29+
// Optional. Will be used only if you choose Redis cache as cache_system
30+
'redis_dsn' => 'redis://localhost:6379',
31+
32+
// Optional. Will be used only if you choose Memcached as cache_system
33+
'memcached_dsn' => 'memcached://localhost:11211',
34+
35+
// Optional. If you use a CDN, a reverse proxy or a load balancer, set an array of IPs.
36+
// For other IPs, the bouncer will not trust the X-Forwarded-For header.
37+
'trust_ip_forward_array' => [],
1638

17-
// Optional. true to enable live mode, false to enable the stream mode. Default to true.
18-
'live_mode'=> true,
39+
// Optional. true to enable stream mode, true to enable the stream mode. Default to false.
40+
'stream_mode'=> false,
1941

20-
// Optional. Cap the remediation to the selected one. Select from 'bypass' (minimum remediation), 'captcha' or 'ban' (maximum remediation). Defaults to 'ban'.
42+
// Optional. true to enable verbose debug log. Default to false
43+
'debug_mode' => false,
44+
45+
// Optional. true to stop the process and display errors if any. Default to false.
46+
'display_errors' => false,
47+
48+
// Optional. true to hide CrowdSec mentions on ban and captcha walls. Default to false.
49+
'hide_mentions' => false,
50+
51+
// Optional. Only for test or debug purpose.
52+
// If not empty, it will be used for all remediation and geolocation processes.
53+
'forced_test_ip' => '1.2.3.4',
54+
55+
// Optional. Cap the remediation to the selected one.
56+
// Select from 'bypass' (minimum remediation),'captcha' or 'ban' (maximum remediation).
57+
// Default to 'ban'.
2158
'max_remediation_level'=> 'ban',
2259

23-
// Optional. Handle unknown remediations as. Select from 'bypass' (minimum remediation), 'captcha' or 'ban' (maximum remediation). Defaults to 'captcha'.
60+
// Optional. Handle unknown remediations as.
61+
// Select from 'bypass' (minimum remediation), 'captcha' or 'ban' (maximum remediation).
62+
// Default to 'captcha'.
2463
'fallback_remediation'=> 'captcha',
2564

2665
// Optional. Set the duration we keep in cache the fact that an IP is clean. In seconds. Defaults to 5.
2766
'cache_expiration_for_clean_ip'=> '5',
2867

2968
// Optional. Set the duration we keep in cache the fact that an IP is bad. In seconds. Defaults to 20.
3069
'cache_expiration_for_bad_ip'=> '20',
70+
71+
// Optional
72+
'hide_mentions' => false
73+
74+
// Optional. Settings for geolocation remediation (i.e. country based remediation).
75+
'geolocation' => [
76+
// Optional. true to enable remediation based on country.
77+
// Default to false.
78+
'enabled' => false,
79+
// Optional. Geolocation system. Only 'maxmind' is available for the moment.
80+
// Default to 'maxmind'
81+
'type' => 'maxmind',
82+
// Optional. true to store the geolocalized country in session
83+
// Setting true will avoid multiple call to the geolocalized system (e.g. maxmind database)
84+
// Default to true.
85+
'save_in_session' => true,
86+
// Optional. MaxMind settings
87+
'maxmind' => [
88+
// Optional. Select from 'country' or 'city'.
89+
// These are the two available MaxMind database types.
90+
// Default to 'country'
91+
'database_type' => 'country',
92+
// Optional. Absolute path to the MaxMind database (mmdb file).
93+
'database_path' => '/some/path/GeoLite2-Country.mmdb',
94+
]
95+
]
3196
]
32-
$cacheAdapter = (...)
33-
$bouncer = new Bouncer($cacheAdapter);
97+
$bouncer = new Bouncer();
3498
$bouncer->configure($config);
3599
```

examples/auto-prepend/scripts/bounce-via-auto-prepend.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,5 @@
77

88
$bounce = new StandAloneBounce();
99

10-
$bounce->setDebug($crowdSecStandaloneBouncerConfig['debug_mode']??false);
11-
$bounce->setDisplayErrors($crowdSecStandaloneBouncerConfig['display_errors'] ?? false);
1210
$bounce->init($crowdSecStandaloneBouncerConfig);
1311
$bounce->safelyBounce();

examples/auto-prepend/scripts/cache-actions.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
if (isset($_GET['action']) && in_array($_GET['action'],['refresh', 'clear', 'prune', 'warm-up'])) {
99
$action = $_GET['action'];
1010
$bounce = new StandAloneBounce();
11-
$bounce->setDebug($crowdSecStandaloneBouncerConfig['debug_mode']??false);
12-
$bounce->setDisplayErrors($crowdSecStandaloneBouncerConfig['display_errors'] ?? false);
1311
$bounce->init($crowdSecStandaloneBouncerConfig);
1412
$bouncer = $bounce->getBouncerInstance();
1513
switch ($action) {

examples/auto-prepend/settings.example.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
'fallback_remediation' => Constants::REMEDIATION_CAPTCHA,
2525

2626
'hide_mentions' => false,
27-
'trust_ip_forward' => '',
2827
'trust_ip_forward_array' => [],
2928

3029
'theme_color_text_primary' => 'black',

examples/live-mode/full-example-live-mode.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
'api_url' => $apiUrl,
4848
'api_user_agent' => 'MyCMS CrowdSec Bouncer/1.0.0',
4949
'api_timeout' => 1,
50-
'live_mode' => true,
50+
'stream_mode' => false,
5151
'max_remediation_level' => 'ban',
5252
'cache_expiration_for_clean_ip' => 2,
5353
'cache_expiration_for_bad_ip' => 30,

src/AbstractBounce.php

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66
require_once __DIR__.'/templates/access-forbidden.php';
77

88
use Bramus\Monolog\Formatter\ColoredLineFormatter;
9+
use ErrorException;
910
use Exception;
1011
use IPLib\Factory;
1112
use Monolog\Formatter\LineFormatter;
1213
use Monolog\Handler\RotatingFileHandler;
1314
use Monolog\Logger;
1415
use Psr\Cache\InvalidArgumentException;
1516
use Psr\Log\LoggerInterface;
17+
use Symfony\Component\Cache\Exception\CacheException;
1618

1719
/**
1820
* The class that apply a bounce.
@@ -41,14 +43,19 @@ abstract class AbstractBounce
4143
/** @var Bouncer */
4244
protected $bouncer;
4345

46+
protected function getBoolSettings(string $name): bool
47+
{
48+
return $this->settings[$name]??false;
49+
}
50+
4451
protected function getStringSettings(string $name): string
4552
{
46-
return $this->settings[$name];
53+
return $this->settings[$name] ?? '';
4754
}
4855

4956
protected function getArraySettings(string $name): array
5057
{
51-
return $this->settings[$name];
58+
return $this->settings[$name] ?? [];
5259
}
5360

5461
/**
@@ -193,6 +200,11 @@ protected function clearCaptchaSessionContext()
193200
$this->unsetSessionVariable('crowdsec_captcha_resolution_failed');
194201
}
195202

203+
/**
204+
* @throws ErrorException
205+
* @throws InvalidArgumentException
206+
* @throws CacheException
207+
*/
196208
protected function handleCaptchaResolutionForm(string $ip)
197209
{
198210
// Early return if no captcha has to be resolved or if captcha already resolved.
@@ -237,6 +249,11 @@ protected function handleCaptchaResolutionForm(string $ip)
237249
}
238250
}
239251

252+
/**
253+
* @throws ErrorException
254+
* @throws InvalidArgumentException
255+
* @throws CacheException
256+
*/
240257
protected function handleCaptchaRemediation($ip)
241258
{
242259
// Check captcha resolution form
@@ -259,6 +276,11 @@ protected function handleCaptchaRemediation($ip)
259276
}
260277
}
261278

279+
/**
280+
* @throws CacheException
281+
* @throws ErrorException
282+
* @throws InvalidArgumentException
283+
*/
262284
protected function handleRemediation(string $remediation, string $ip)
263285
{
264286
if (Constants::REMEDIATION_CAPTCHA !== $remediation && null !== $this->getSessionVariable('crowdsec_captcha_has_to_be_resolved')) {

src/ApiCache.php

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class ApiCache
4848
private $geolocation;
4949

5050
/** @var bool */
51-
private $liveMode = false;
51+
private $streamMode = false;
5252

5353
/**
5454
* @var int
@@ -101,7 +101,7 @@ public function __construct(LoggerInterface $logger, ApiClient $apiClient = null
101101
/**
102102
* Configure this instance.
103103
*
104-
* @param bool $liveMode If we use the live mode (else we use the stream mode)
104+
* @param bool $streamMode If we use the stream mode (else we use the live mode)
105105
* @param string $apiUrl The URL of the LAPI
106106
* @param int $timeout The timeout well calling LAPI
107107
* @param string $userAgent The user agent to use when calling LAPI
@@ -114,7 +114,7 @@ public function __construct(LoggerInterface $logger, ApiClient $apiClient = null
114114
* @throws InvalidArgumentException
115115
*/
116116
public function configure(
117-
bool $liveMode,
117+
bool $streamMode,
118118
string $apiUrl,
119119
int $timeout,
120120
string $userAgent,
@@ -124,7 +124,7 @@ public function configure(
124124
string $fallbackRemediation,
125125
array $geolocConfig = []
126126
): void {
127-
$this->liveMode = $liveMode;
127+
$this->streamMode = $streamMode;
128128
$this->cacheExpirationForCleanIp = $cacheExpirationForCleanIp;
129129
$this->cacheExpirationForBadIp = $cacheExpirationForBadIp;
130130
$this->fallbackRemediation = $fallbackRemediation;
@@ -136,7 +136,7 @@ public function configure(
136136
$this->logger->debug('', [
137137
'type' => 'API_CACHE_INIT',
138138
'adapter' => \get_class($this->adapter),
139-
'mode' => ($liveMode ? 'live' : 'stream'),
139+
'mode' => ($streamMode ? 'stream' : 'live'),
140140
'exp_clean_ips' => $cacheExpirationForCleanIp,
141141
'exp_bad_ips' => $cacheExpirationForBadIp,
142142
'warmed_up' => ($this->warmedUp ? 'true' : 'false'),
@@ -295,7 +295,7 @@ private function formatRemediationFromDecision(?array $decision): array
295295
{
296296
if (!$decision) {
297297
$duration = time() + $this->cacheExpirationForCleanIp;
298-
if (!$this->liveMode) {
298+
if ($this->streamMode) {
299299
// In stream mode we consider a clean IP forever... until the next resync.
300300
$duration = 315360000; // in this case, forever is 10 years as PHP_INT_MAX will cause trouble with the Memcached Adapter (int to float unwanted conversion)
301301
}
@@ -306,7 +306,7 @@ private function formatRemediationFromDecision(?array $decision): array
306306
$duration = self::parseDurationToSeconds($decision['duration']);
307307

308308
// Don't set a max duration in stream mode to avoid bugs. Only the stream update has to change the cache state.
309-
if ($this->liveMode) {
309+
if (!$this->streamMode) {
310310
$duration = min($this->cacheExpirationForBadIp, $duration);
311311
}
312312

@@ -659,7 +659,7 @@ private function miss(string $value, string $cacheScope): string
659659
{
660660
$decisions = [];
661661
$cacheKey = $this->getCacheKey($cacheScope, $value);
662-
if ($this->liveMode) {
662+
if (!$this->streamMode) {
663663
if (Constants::SCOPE_IP === $cacheScope) {
664664
$this->logger->debug('', ['type' => 'DIRECT_API_CALL', 'ip' => $value]);
665665
$decisions = $this->apiClient->getFilteredDecisions(['ip' => $value]);
@@ -694,8 +694,10 @@ private function hit(string $ip): string
694694
}
695695

696696
/**
697+
* @param string $cacheScope
697698
* @param $value
698699
*
700+
* @return string
699701
* @throws InvalidArgumentException
700702
* @throws Exception
701703
*/
@@ -738,7 +740,7 @@ public function get(AddressInterface $address): string
738740
$ip = $address->toString();
739741
$this->logger->debug('', ['type' => 'START_IP_CHECK', 'ip' => $ip]);
740742

741-
if (!$this->liveMode && !$this->warmedUp) {
743+
if ($this->streamMode && !$this->warmedUp) {
742744
throw new BouncerException('CrowdSec Bouncer configured in "stream" mode. Please warm the cache up before trying to access it.');
743745
}
744746

src/Bouncer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public function configure(array $config): void
7373

7474
// Configure Api Cache.
7575
$this->apiCache->configure(
76-
$this->config['live_mode'],
76+
$this->config['stream_mode'],
7777
$this->config['api_url'],
7878
$this->config['api_timeout'],
7979
$this->config['api_user_agent'],

src/Configuration.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,24 @@ public function getConfigTreeBuilder(): TreeBuilder
3232
->scalarNode('api_url')->defaultValue(Constants::CAPI_URL)->end()
3333
->scalarNode('api_user_agent')->defaultValue(Constants::BASE_USER_AGENT)->end()
3434
->integerNode('api_timeout')->defaultValue(Constants::API_TIMEOUT)->end()
35-
->booleanNode('live_mode')->defaultValue(true)->end()
35+
->booleanNode('stream_mode')->defaultValue(false)->end()
36+
->booleanNode('debug_mode')->defaultValue(false)->end()
37+
->booleanNode('display_errors')->defaultValue(false)->end()
38+
->booleanNode('hide_mentions')->defaultValue(false)->end()
3639
->scalarNode('forced_test_ip')->end()
40+
->scalarNode('log_directory_path')->end()
41+
->enumNode('bouncing_level')
42+
->values([Constants::BOUNCING_LEVEL_DISABLED, Constants::BOUNCING_LEVEL_NORMAL, Constants::BOUNCING_LEVEL_FLEX])
43+
->defaultValue(Constants::BOUNCING_LEVEL_NORMAL)
44+
->end()
45+
->enumNode('cache_system')
46+
->values([Constants::CACHE_SYSTEM_PHPFS, Constants::CACHE_SYSTEM_REDIS, Constants::CACHE_SYSTEM_MEMCACHED])
47+
->defaultValue(Constants::CACHE_SYSTEM_PHPFS)
48+
->end()
49+
->scalarNode('fs_cache_path')->end()
50+
->scalarNode('redis_dsn')->end()
51+
->scalarNode('memcached_dsn')->end()
52+
->arrayNode('trust_ip_forward_array')->end()
3753
->enumNode('max_remediation_level')
3854
->values(Constants::ORDERED_REMEDIATIONS)
3955
->defaultValue(Constants::REMEDIATION_BAN)

0 commit comments

Comments
 (0)