Skip to content

Commit 14bd628

Browse files
committed
Added: support for running as file in mu-plugins, documentation will follow.
Fixed: fatal error due to type in ctype_digit. Fixed: issue with rule that contained sub-rules. Fixed: if open redirect matching type value contains no protocol, add it ourselves so parse_url does not fail.
1 parent 7599c7a commit 14bd628

2 files changed

Lines changed: 53 additions & 8 deletions

File tree

src/Processor.php

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ class Processor
4545
'autoblockAttempts' => 10,
4646
'autoblockMinutes' => 30,
4747
'autoblockTime' => 60,
48-
'whitelistKeysRules' => []
48+
'whitelistKeysRules' => [],
49+
'mustUsePluginCall' => false
4950
];
5051

5152
/**
@@ -122,13 +123,17 @@ public function __get($name)
122123
public function launch($mustExit = true)
123124
{
124125
// Determine if the user is temporarily blocked from the site before we do anything else.
125-
if ($this->extension->isBlocked($this->autoblockMinutes, $this->autoblockTime, $this->autoblockAttempts) && !$this->extension->canBypass()) {
126+
if (
127+
$this->extension->isBlocked($this->autoblockMinutes, $this->autoblockTime, $this->autoblockAttempts) && (
128+
$this->mustUsePluginCall || (!$this->mustUsePluginCall && !$this->extension->canBypass())
129+
)
130+
) {
126131
$this->extension->forceExit(22);
127132
}
128133

129134
// Check for whitelist based on the legacy whitelist rules.
130135
$request = $this->request->capture();
131-
if ($this->extension->isWhitelisted($this->whitelistRulesLegacy, $request)) {
136+
if (!$this->mustUsePluginCall && $this->extension->isWhitelisted($this->whitelistRulesLegacy, $request)) {
132137
return true;
133138
}
134139

@@ -143,7 +148,7 @@ public function launch($mustExit = true)
143148
}
144149

145150
// Determine if the current request is whitelisted or not (role based).
146-
$isWhitelisted = $this->extension->canBypass();
151+
$isWhitelisted = !$this->mustUsePluginCall && $this->extension->canBypass();
147152

148153
// Merge the rules together. First iterate through the whitelist rules.
149154
$rules = array_merge($this->whitelistRules, $this->firewallRules);
@@ -158,6 +163,12 @@ public function launch($mustExit = true)
158163
continue;
159164
}
160165

166+
// If the rule contains matching type we cannot call during mu-plugins, skip.
167+
$hasWpAction = $this->hasWpAction($rule['rules']);
168+
if (defined('PS_FW_MU_RAN') && !$hasWpAction || $this->mustUsePluginCall && $hasWpAction) {
169+
continue;
170+
}
171+
161172
// Execute the firewall rule.
162173
$rule_hit = $this->executeFirewall($rule['rules']);
163174

@@ -187,7 +198,7 @@ public function launch($mustExit = true)
187198
}
188199

189200
// Run the legacy firewall rules processor for backwards compatibility.
190-
if (count($this->firewallRulesLegacy) > 0) {
201+
if (count($this->firewallRulesLegacy) > 0 && !$this->mustUsePluginCall) {
191202
$this->launchLegacy(true, $request, $this->extension->getIpAddress());
192203
}
193204

@@ -220,7 +231,7 @@ public function executeFirewall($rules)
220231

221232
// Extract the value of the paramater that we want.
222233
$value = $this->request->getParameterValue($rule['parameter']);
223-
if (is_null($value) && $rule['parameter'] !== false) {
234+
if (is_null($value) && $rule['parameter'] !== false && $rule['parameter'] != 'rules') {
224235
continue;
225236
}
226237

@@ -349,7 +360,7 @@ public function matchParameterValue($match, $value)
349360
}
350361

351362
// If the user does not have a WP privilege.
352-
if ($matchType == 'current_user_cannot' && is_scalar($matchValue) && function_exists('current_user_can')) {
363+
if ($matchType == 'current_user_cannot' && is_scalar($matchValue) && function_exists('current_user_can') && !$this->mustUsePluginCall) {
353364
return @!current_user_can($matchValue);
354365
}
355366

@@ -380,6 +391,11 @@ public function matchParameterValue($match, $value)
380391
return false;
381392
}
382393

394+
// If there's no protocol we add it.
395+
if (substr($value, 0, 4) != 'http') {
396+
$value = 'https://' . $value;
397+
}
398+
383399
// We only care about the hostname.
384400
$host = parse_url($value, PHP_URL_HOST);
385401
if (!$host) {
@@ -425,6 +441,35 @@ public function matchParameterValue($match, $value)
425441
return false;
426442
}
427443

444+
/**
445+
* Determine if the rules contain an action that should not be executed under the mu-plugins context.
446+
*
447+
* @param array $rules
448+
* @return boolean
449+
*/
450+
private function hasWpAction($rules)
451+
{
452+
$functions = ['current_user_cannot'];
453+
454+
if (isset($rules['rules'])) {
455+
if ($this->hasWpAction($rules['rules'])) {
456+
return true;
457+
}
458+
}
459+
460+
foreach ($rules as $rule) {
461+
if (!isset($rule['match'], $rule['match']['type'])) {
462+
continue;
463+
}
464+
465+
if (in_array($rule['match']['type'], $functions)) {
466+
return true;
467+
}
468+
}
469+
470+
return false;
471+
}
472+
428473
/**
429474
* The legacy firewall processor will only iterate over the general legacy firewall rules.
430475
* Will return true if $mustExit is false and all of the rules were processed without a positive detection.

src/Request.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public function __construct($options, ExtensionInterface $extension)
4242
public function getParameterValue($parameter, $data = [])
4343
{
4444
// For when a rule contains sub-rules.
45-
if (ctype_digit($parameter) || empty($parameter)) {
45+
if (empty($parameter) || ctype_digit($parameter)) {
4646
return null;
4747
}
4848

0 commit comments

Comments
 (0)