Skip to content

Commit 424e5c4

Browse files
feat(metrics): Add reset metrics feature (#137)
* feat(metrics): Add a method to reset metrics and check Blaas URI * test(reset metrics): Add code coverage * docs(changelog): Prepare 4.3.0 release * style(*): Remove trailing comma for 7.2
1 parent 9d5d167 commit 424e5c4

File tree

6 files changed

+148
-1
lines changed

6 files changed

+148
-1
lines changed

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,18 @@ As far as possible, we try to adhere to [Symfony guidelines](https://symfony.com
1111

1212
---
1313

14+
## [4.3.0](https://github.com/crowdsecurity/php-cs-bouncer/releases/tag/v4.3.0) - 2025-05-??
15+
[_Compare with previous release_](https://github.com/crowdsecurity/php-cs-bouncer/compare/v4.2.0...HEAD)
16+
17+
__This release is not published yet__
18+
19+
### Added
20+
21+
- Add `hasBlaasUri` to detect if the bouncer is connected to a Block As A Service Lapi
22+
- Add `resetUsageMetrics` to reset the usage metrics cache item
23+
24+
---
25+
1426
## [4.2.0](https://github.com/crowdsecurity/php-cs-bouncer/releases/tag/v4.2.0) - 2025-01-31
1527
[_Compare with previous release_](https://github.com/crowdsecurity/php-cs-bouncer/compare/v4.1.0...v4.2.0)
1628

docs/USER_GUIDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ Below is the list of available settings:
299299

300300

301301
- `captcha_cache_duration`: Set the duration we keep in cache the captcha flow variables for an IP. In seconds.
302-
Defaults to 86400.. In seconds. Defaults to 20.
302+
Defaults to 86400.
303303

304304

305305
### Geolocation

src/AbstractBouncer.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,16 @@ abstract public function getRequestUri(): string;
225225
*/
226226
abstract public function getRequestUserAgent(): string;
227227

228+
/**
229+
* Check if the bouncer is connected to a "Blocklist as a service" Lapi.
230+
*/
231+
public function hasBlaasUri(): bool
232+
{
233+
$url = $this->getRemediationEngine()->getClient()->getConfig('api_url');
234+
235+
return 0 === strpos($url, Constants::BLAAS_URL);
236+
}
237+
228238
/**
229239
* This method prune the cache: it removes all the expired cache items.
230240
*
@@ -276,6 +286,20 @@ public function refreshBlocklistCache(): array
276286
}
277287
}
278288

289+
/**
290+
* @throws InvalidArgumentException
291+
*/
292+
public function resetUsageMetrics(): void
293+
{
294+
// Retrieve metrics cache item
295+
$metricsItem = $this->getRemediationEngine()->getCacheStorage()->getItem(AbstractCache::ORIGINS_COUNT);
296+
if ($metricsItem->isHit()) {
297+
// Reset the metrics
298+
$metricsItem->set([]);
299+
$this->getRemediationEngine()->getCacheStorage()->getAdapter()->save($metricsItem);
300+
}
301+
}
302+
279303
/**
280304
* Handle a bounce for current IP.
281305
*

src/Constants.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
*/
1919
class Constants extends RemConstants
2020
{
21+
/** @var string The URL prefix for Blocklist as a service LAPI */
22+
public const BLAAS_URL = 'https://admin.api.crowdsec.net';
2123
/** @var int The duration we keep a captcha flow in cache */
2224
public const CACHE_EXPIRATION_FOR_CAPTCHA = 86400;
2325
/** @var string The "MEMCACHED" cache system */

tests/Integration/AbstractBouncerTest.php

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
* @covers \CrowdSecBouncer\AbstractBouncer::shouldBounceCurrentIp
8282
* @covers \CrowdSecBouncer\AbstractBouncer::handleBounceExclusion
8383
* @covers \CrowdSecBouncer\AbstractBouncer::pushUsageMetrics
84+
* @covers \CrowdSecBouncer\AbstractBouncer::resetUsageMetrics
8485
*/
8586
final class AbstractBouncerTest extends TestCase
8687
{
@@ -1053,6 +1054,89 @@ public function testRun()
10531054
);
10541055
}
10551056

1057+
public function testResetMetrics()
1058+
{
1059+
$client = new BouncerClient($this->configs, null, $this->logger);
1060+
$cache = new PhpFiles($this->configs, $this->logger);
1061+
$originCountItem = $cache->getItem(AbstractCache::ORIGINS_COUNT)->get();
1062+
$this->assertEquals(
1063+
null,
1064+
$originCountItem,
1065+
'The origin count for clean should be empty'
1066+
);
1067+
1068+
// bouncing URI
1069+
$client = new BouncerClient($this->configs, null, $this->logger);
1070+
$cache = new PhpFiles($this->configs, $this->logger);
1071+
$lapiRemediation = new LapiRemediation($this->configs, $client, $cache, $this->logger);
1072+
// Mock sendResponse and redirectResponse to avoid PHP UNIT header already sent or exit error
1073+
$bouncer = $this->getMockForAbstractClass(AbstractBouncer::class, [$this->configs, $lapiRemediation, $this->logger],
1074+
'', true,
1075+
true, true, [
1076+
'sendResponse',
1077+
'redirectResponse',
1078+
'getHttpMethod',
1079+
'getPostedVariable',
1080+
'getHttpRequestHeader',
1081+
'getRemoteIp',
1082+
'getRequestUri',
1083+
]);
1084+
1085+
$bouncer->method('getRequestUri')->willReturnOnConsecutiveCalls('/home');
1086+
$bouncer->method('getRemoteIp')->willReturnOnConsecutiveCalls('127.0.0.3');
1087+
$this->assertEquals(true, $bouncer->run(), 'Should bounce uri');
1088+
$originCountItem = $cache->getItem(AbstractCache::ORIGINS_COUNT)->get();
1089+
$this->assertEquals(
1090+
['clean' => ['bypass' => 1]],
1091+
$originCountItem,
1092+
'The origin count for clean should be 1'
1093+
);
1094+
1095+
// Test no-forward
1096+
$bouncerConfigs = array_merge(
1097+
$this->configs,
1098+
[
1099+
'forced_test_forwarded_ip' => Constants::X_FORWARDED_DISABLED,
1100+
]
1101+
);
1102+
$client = new BouncerClient($bouncerConfigs, null, $this->logger);
1103+
$cache = new PhpFiles($bouncerConfigs, $this->logger);
1104+
$lapiRemediation = new LapiRemediation($bouncerConfigs, $client, $cache, $this->logger);
1105+
// Mock sendResponse and redirectResponse to avoid PHP UNIT header already sent or exit error
1106+
$bouncer = $this->getMockForAbstractClass(AbstractBouncer::class, [$bouncerConfigs, $lapiRemediation, $this->logger],
1107+
'', true,
1108+
true, true, [
1109+
'sendResponse',
1110+
'redirectResponse',
1111+
'getHttpMethod',
1112+
'getPostedVariable',
1113+
'getHttpRequestHeader',
1114+
'getRemoteIp',
1115+
'getRequestUri',
1116+
]);
1117+
1118+
$bouncer->method('getRequestUri')->willReturnOnConsecutiveCalls('/home');
1119+
$bouncer->method('getRemoteIp')->willReturnOnConsecutiveCalls('127.0.0.7');
1120+
1121+
$bouncer->run();
1122+
1123+
$originCountItem = $cache->getItem(AbstractCache::ORIGINS_COUNT)->get();
1124+
$this->assertEquals(
1125+
['clean' => ['bypass' => 2]],
1126+
$originCountItem,
1127+
'The origin count for clean should be 2'
1128+
);
1129+
1130+
// Test: reset metrics
1131+
$result = $bouncer->resetUsageMetrics();
1132+
$originCountItem = $cache->getItem(AbstractCache::ORIGINS_COUNT)->get();
1133+
$this->assertEquals(
1134+
[],
1135+
$originCountItem,
1136+
'The origin count item should be reset'
1137+
);
1138+
}
1139+
10561140
public function testPrivateAndProtectedMethods()
10571141
{
10581142
// handleCache

tests/Unit/AbstractBouncerTest.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
* @uses \CrowdSecBouncer\AbstractBouncer::handleBounceExclusion
7878
*
7979
* @covers \CrowdSecBouncer\AbstractBouncer::pushUsageMetrics
80+
* @covers \CrowdSecBouncer\AbstractBouncer::hasBlaasUri
8081
*/
8182
final class AbstractBouncerTest extends TestCase
8283
{
@@ -774,6 +775,30 @@ public function testPushUsageMetricsException()
774775
$this->assertEquals('Error in unit test', $errorMessage);
775776
}
776777

778+
public function testHasBlockAsAServiceUri()
779+
{
780+
$configs = $this->configs;
781+
$client = new BouncerClient($configs);
782+
$cache = new PhpFiles($configs);
783+
$lapiRemediation = new LapiRemediation($configs, $client, $cache);
784+
$bouncer = $this->getMockForAbstractClass(AbstractBouncer::class, [$configs, $lapiRemediation]);
785+
786+
$result = $bouncer->hasBlaasUri();
787+
$this->assertEquals(false, $result);
788+
789+
$configs = array_merge($this->configs, [
790+
'api_url' => 'https://admin.api.crowdsec.net',
791+
]);
792+
793+
$client = new BouncerClient($configs);
794+
$cache = new PhpFiles($configs);
795+
$lapiRemediation = new LapiRemediation($configs, $client, $cache);
796+
$bouncer = $this->getMockForAbstractClass(AbstractBouncer::class, [$configs, $lapiRemediation]);
797+
798+
$result = $bouncer->hasBlaasUri();
799+
$this->assertEquals(true, $result);
800+
}
801+
777802
public function testShouldBounceCurrentIp()
778803
{
779804
$configs = $this->configs;

0 commit comments

Comments
 (0)