Skip to content

Commit a5b2a2b

Browse files
committed
add standalone mode
1 parent b22213b commit a5b2a2b

File tree

11 files changed

+365
-206
lines changed

11 files changed

+365
-206
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ crowdsec-wp*
1616
.cache/
1717
*.log
1818
.vagrant
19-
.env
19+
.env
20+
inc/standalone-settings.php

crowdsec.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ class WordpressCrowdSecBouncerException extends \RuntimeException
3030
}
3131

3232
require_once __DIR__.'/inc/constants.php';
33+
$crowdsecRandomLogFolder = get_option('crowdsec_random_log_folder') ?: '';
34+
crowdsecDefineConstants($crowdsecRandomLogFolder);
3335
require_once __DIR__.'/inc/scheduling.php';
3436
require_once __DIR__.'/inc/plugin-setup.php';
3537
register_activation_hook(__FILE__, 'activate_crowdsec_plugin');
@@ -38,7 +40,4 @@ class WordpressCrowdSecBouncerException extends \RuntimeException
3840
require_once __DIR__.'/inc/admin/init.php';
3941
require_once __DIR__.'/inc/bounce-current-ip.php';
4042

41-
// Apply bouncing via Wordpress instanciation, only if standalone mode is disabled.
42-
if ((bool) get_option('crowdsec_standalone_mode')) {
43-
add_action('plugins_loaded', 'safelyBounceCurrentIp');
44-
}
43+
add_action('plugins_loaded', 'safelyBounceCurrentIp');

docker-compose.yml

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ services:
2828
build:
2929
context: .
3030
dockerfile: ./docker/php-${CS_WORDPRESS_BOUNCER_PHP_VERSION}.Dockerfile
31-
networks:
31+
networks:
3232
- wordpress_bouncer_network_ipv4
3333
- wordpress_bouncer_network_ipv6
3434
depends_on:
@@ -46,12 +46,13 @@ services:
4646
- "80:80"
4747
volumes:
4848
- .:/var/www/html/wp-content/plugins/cs-wordpress-bouncer:rw
49+
- ./docker/tests.htaccess:/var/www/html/.htaccess:rw
4950

5051
wordpress5-5:
5152
build:
5253
context: .
5354
dockerfile: ./docker/wp5.5/php-${CS_WORDPRESS_BOUNCER_PHP_VERSION}.Dockerfile
54-
networks:
55+
networks:
5556
- wordpress_bouncer_network_ipv4
5657
- wordpress_bouncer_network_ipv6
5758
depends_on:
@@ -69,12 +70,13 @@ services:
6970
- "80:80"
7071
volumes:
7172
- .:/var/www/html/wp-content/plugins/cs-wordpress-bouncer:rw
72-
73+
- ./docker/tests.htaccess:/var/www/html/.htaccess:rw
74+
7375
wordpress5-4:
7476
build:
7577
context: .
7678
dockerfile: ./docker/wp5.4/php-${CS_WORDPRESS_BOUNCER_PHP_VERSION}.Dockerfile
77-
networks:
79+
networks:
7880
- wordpress_bouncer_network_ipv4
7981
- wordpress_bouncer_network_ipv6
8082
depends_on:
@@ -92,12 +94,13 @@ services:
9294
- "80:80"
9395
volumes:
9496
- .:/var/www/html/wp-content/plugins/cs-wordpress-bouncer:rw
95-
97+
- ./docker/tests.htaccess:/var/www/html/.htaccess:rw
98+
9699
wordpress5-3:
97100
build:
98101
context: .
99102
dockerfile: ./docker/wp5.3/php-${CS_WORDPRESS_BOUNCER_PHP_VERSION}.Dockerfile
100-
networks:
103+
networks:
101104
- wordpress_bouncer_network_ipv4
102105
- wordpress_bouncer_network_ipv6
103106
depends_on:
@@ -115,12 +118,13 @@ services:
115118
- "80:80"
116119
volumes:
117120
- .:/var/www/html/wp-content/plugins/cs-wordpress-bouncer:rw
121+
- ./docker/tests.htaccess:/var/www/html/.htaccess:rw
118122

119123
wordpress5-2:
120124
build:
121125
context: .
122126
dockerfile: ./docker/wp5.2/php-${CS_WORDPRESS_BOUNCER_PHP_VERSION}.Dockerfile
123-
networks:
127+
networks:
124128
- wordpress_bouncer_network_ipv4
125129
- wordpress_bouncer_network_ipv6
126130
depends_on:
@@ -138,12 +142,13 @@ services:
138142
- "80:80"
139143
volumes:
140144
- .:/var/www/html/wp-content/plugins/cs-wordpress-bouncer:rw
145+
- ./docker/tests.htaccess:/var/www/html/.htaccess:rw
141146

142147
wordpress5-1:
143148
build:
144149
context: .
145150
dockerfile: ./docker/wp5.1/php-${CS_WORDPRESS_BOUNCER_PHP_VERSION}.Dockerfile
146-
networks:
151+
networks:
147152
- wordpress_bouncer_network_ipv4
148153
- wordpress_bouncer_network_ipv6
149154
depends_on:
@@ -166,7 +171,7 @@ services:
166171
build:
167172
context: .
168173
dockerfile: ./docker/wp5.0/php-${CS_WORDPRESS_BOUNCER_PHP_VERSION}.Dockerfile
169-
networks:
174+
networks:
170175
- wordpress_bouncer_network_ipv4
171176
- wordpress_bouncer_network_ipv6
172177
depends_on:
@@ -184,12 +189,13 @@ services:
184189
- "80:80"
185190
volumes:
186191
- .:/var/www/html/wp-content/plugins/cs-wordpress-bouncer:rw
192+
- ./docker/tests.htaccess:/var/www/html/.htaccess:rw
187193

188194
wordpress4-9:
189195
build:
190196
context: .
191197
dockerfile: ./docker/wp4.9/php-${CS_WORDPRESS_BOUNCER_PHP_VERSION}.Dockerfile
192-
networks:
198+
networks:
193199
- wordpress_bouncer_network_ipv4
194200
- wordpress_bouncer_network_ipv6
195201
depends_on:
@@ -207,10 +213,11 @@ services:
207213
- "80:80"
208214
volumes:
209215
- .:/var/www/html/wp-content/plugins/cs-wordpress-bouncer:rw
216+
- ./docker/tests.htaccess:/var/www/html/.htaccess:rw
210217

211218
crowdsec:
212219
image: crowdsecurity/crowdsec:latest
213-
networks:
220+
networks:
214221
- wordpress_bouncer_network_ipv4
215222
- wordpress_bouncer_network_ipv6
216223
environment:
@@ -219,30 +226,30 @@ services:
219226
- "8051:8080"
220227
mysql:
221228
image: mysql:5.7
222-
networks:
229+
networks:
223230
- wordpress_bouncer_network_ipv4
224231
- wordpress_bouncer_network_ipv6
225232
environment:
226233
- MYSQL_ROOT_PASSWORD=super_secret_password
227234
- MYSQL_DATABASE=wordpress
228235
redis:
229236
image: redis:6-alpine
230-
networks:
237+
networks:
231238
- wordpress_bouncer_network_ipv4
232239
- wordpress_bouncer_network_ipv6
233240
memcached:
234241
image: memcached:1-alpine
235-
networks:
242+
networks:
236243
- wordpress_bouncer_network_ipv4
237244
- wordpress_bouncer_network_ipv6
238245
wpscan:
239246
image: wpscanteam/wpscan
240-
networks:
247+
networks:
241248
- wordpress_bouncer_network_ipv4
242249
- wordpress_bouncer_network_ipv6
243250
e2e:
244251
image: mcr.microsoft.com/playwright:focal
245-
networks:
252+
networks:
246253
- wordpress_bouncer_network_ipv4
247254
- wordpress_bouncer_network_ipv6
248255
environment:
@@ -269,11 +276,11 @@ networks:
269276
enable_ipv6: false
270277
ipam:
271278
config:
272-
- subnet: ${NETWORK_SUBNET}
279+
- subnet: ${NETWORK_SUBNET}
273280
wordpress_bouncer_network_ipv6:
274281
name: wordpress_bouncer_network
275282
enable_ipv6: true
276283
ipam:
277284
config:
278-
- subnet: 2001:3200:3200::/64
279-
gateway: 2001:3200:3200::1
285+
- subnet: 2001:3200:3200::/64
286+
gateway: 2001:3200:3200::1

docker/tests.htaccess

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
2+
# BEGIN WordPress
3+
# The directives (lines) between "BEGIN WordPress" and "END WordPress" are
4+
# dynamically generated, and should only be modified via WordPress filters.
5+
# Any changes to the directives between these markers will be overwritten.
6+
<IfModule mod_rewrite.c>
7+
RewriteEngine On
8+
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
9+
RewriteBase /
10+
RewriteRule ^index\.php$ - [L]
11+
RewriteCond %{REQUEST_FILENAME} !-f
12+
RewriteCond %{REQUEST_FILENAME} !-d
13+
RewriteRule . /index.php [L]
14+
</IfModule>
15+
16+
# END WordPress

inc/Bounce.php

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<?php
22

3+
require_once __DIR__.'/constants.php';
4+
35
use CrowdSecBouncer\AbstractBounce;
46
use CrowdSecBouncer\Bouncer;
57
use CrowdSecBouncer\Constants;
@@ -20,28 +22,26 @@ class Bounce extends AbstractBounce implements IBounce
2022
public function init(array $crowdSecConfig): bool
2123
{
2224
$this->settings = $crowdSecConfig;
25+
$crowdsecRandomLogFolder = $this->settings['crowdsec_random_log_folder'];
26+
crowdsecDefineConstants($crowdsecRandomLogFolder);
2327
$this->initLogger();
2428

2529
return true;
2630
}
2731

2832
protected function getSettings(string $name)
2933
{
30-
if (!array_key_exists($name, $this->settings)) {
31-
$this->settings[$name] = get_option($name);
32-
}
33-
3434
return $this->settings[$name];
3535
}
3636

3737
protected function escape(string $value)
3838
{
39-
return esc_attr($value);
39+
return htmlspecialchars($value, \ENT_QUOTES, 'UTF-8');
4040
}
4141

4242
protected function specialcharsDecodeEntQuotes(string $value)
4343
{
44-
return wp_specialchars_decode($value, \ENT_QUOTES);
44+
return htmlspecialchars_decode($value, \ENT_QUOTES);
4545
}
4646

4747
/**
@@ -59,10 +59,15 @@ public function getBouncerInstance(): Bouncer
5959
$crowdSecBouncerUserAgent = CROWDSEC_BOUNCER_USER_AGENT;
6060
$crowdSecLogPath = CROWDSEC_LOG_PATH;
6161
$crowdSecDebugLogPath = CROWDSEC_DEBUG_LOG_PATH;
62-
$debugMode = (bool) WP_DEBUG;
6362

64-
$this->logger = getStandAloneCrowdSecLoggerInstance($crowdSecLogPath, $debugMode, $crowdSecDebugLogPath);
65-
$this->bouncer = getBouncerInstanceStandAlone($apiUrl, $apiKey, $isStreamMode, $cleanIpCacheDuration, $badIpCacheDuration, $fallbackRemediation, $bouncingLevel, $crowdSecBouncerUserAgent, $this->logger);
63+
$this->logger = getStandAloneCrowdSecLoggerInstance($crowdSecLogPath, $this->debug, $crowdSecDebugLogPath);
64+
65+
$cacheSystem = $this->escape($this->getSettings('crowdsec_cache_system'));
66+
$memcachedDsn = $this->escape($this->getSettings('crowdsec_memcached_dsn'));
67+
$redisDsn = $this->escape($this->getSettings('crowdsec_redis_dsn'));
68+
$fsCachePath = CROWDSEC_CACHE_PATH;
69+
70+
$this->bouncer = getBouncerInstanceStandAlone($apiUrl, $apiKey, $isStreamMode, $cleanIpCacheDuration, $badIpCacheDuration, $fallbackRemediation, $bouncingLevel, $crowdSecBouncerUserAgent, $this->logger, $cacheSystem, $memcachedDsn, $redisDsn, $fsCachePath);
6671

6772
return $this->bouncer;
6873
}
@@ -227,16 +232,37 @@ public function shouldBounceCurrentIp(): bool
227232
return false;
228233
}
229234

235+
// Don't bounce if standalone mode is enable and we are not in a auto_prepend_file context.
236+
if ((bool) $this->getSettings('crowdsec_standalone_mode') && !defined('CROWDSEC_STANDALONE_RUNNING_CONTEXT')) {
237+
return false;
238+
}
239+
230240
$shouldNotBounceWpAdmin = !empty($this->getSettings('crowdsec_public_website_only'));
231241
// when the "crowdsec_public_website_only" is disabled...
232242
if ($shouldNotBounceWpAdmin) {
233-
// ...don't bounce back office pages
234-
if (is_admin()) {
235-
return false;
236-
}
237-
// ...don't bounce wp-login and wp-cron pages
238-
if (in_array($GLOBALS['pagenow'], ['wp-login.php', 'wp-cron.php'])) {
239-
return false;
243+
// In standalone context, is_admin() does not work. So we check admin section with another method.
244+
if (defined('CROWDSEC_STANDALONE_RUNNING_CONTEXT')) {
245+
// TODO improve the way to detect these pages or add a warning near to the wp option "enable standalone mode"
246+
// ...don't bounce back office pages
247+
if (0 === strpos($_SERVER['PHP_SELF'], '/wp-admin')) {
248+
return false;
249+
}
250+
// ...don't bounce wp-login and wp-cron pages
251+
if (0 === strpos($_SERVER['PHP_SELF'], '/wp-login.php')) {
252+
return false;
253+
}
254+
if (0 === strpos($_SERVER['PHP_SELF'], '/wp-cron.php')) {
255+
return false;
256+
}
257+
} else {
258+
// ...don't bounce back office pages
259+
if (is_admin()) {
260+
return false;
261+
}
262+
// ...don't bounce wp-login and wp-cron pages
263+
if (in_array($GLOBALS['pagenow'], ['wp-login.php', 'wp-cron.php'])) {
264+
return false;
265+
}
240266
}
241267
}
242268

@@ -343,9 +369,8 @@ public function isConfigValid(): bool
343369

344370
public function initLogger(): void
345371
{
346-
$debugMode = (bool) WP_DEBUG;
347372
$crowdSecLogPath = CROWDSEC_LOG_PATH;
348373
$crowdSecDebugLogPath = CROWDSEC_DEBUG_LOG_PATH;
349-
$this->logger = getStandAloneCrowdSecLoggerInstance($crowdSecLogPath, $debugMode, $crowdSecDebugLogPath);
374+
$this->logger = getStandAloneCrowdSecLoggerInstance($crowdSecLogPath, $this->debug, $crowdSecDebugLogPath);
350375
}
351376
}

0 commit comments

Comments
 (0)