diff --git a/lib/Cleantalk/ApbctWP/Firewall/AntiCrawler.php b/lib/Cleantalk/ApbctWP/Firewall/AntiCrawler.php index bc3e267e9..9c82db2b3 100644 --- a/lib/Cleantalk/ApbctWP/Firewall/AntiCrawler.php +++ b/lib/Cleantalk/ApbctWP/Firewall/AntiCrawler.php @@ -251,11 +251,12 @@ private function runLogSearchForIpPool($ip_array) * * @param string $ip * @param string $status + * @param bool $is_personal * @return array */ - private function makeResult($ip, $status) + private function makeResult($ip, $status, $is_personal = false) { - return array('ip' => $ip, 'is_personal' => false, 'status' => $status); + return array('ip' => $ip, 'is_personal' => $is_personal, 'status' => $status); } /** @@ -294,9 +295,12 @@ private function performUaCheck($current_ip) } // Blacklisted — record but continue to cookie check + // HardCode - write AC dined by UA as personal: blacklisted user-agent may be only personally + // `is_personal` makes priority bigger, but we don't have a personal flag in the AC module yet, so this fix is needed + $is_personal = true; return array( - 'entries' => array($this->makeResult($current_ip, 'DENY_ANTICRAWLER_UA')), - 'early_return' => false, + 'entries' => array($this->makeResult($current_ip, 'DENY_ANTICRAWLER_UA', $is_personal)), + 'early_return' => true, ); } } diff --git a/lib/Cleantalk/Common/Firewall.php b/lib/Cleantalk/Common/Firewall.php index 1360f2796..628fa91a8 100644 --- a/lib/Cleantalk/Common/Firewall.php +++ b/lib/Cleantalk/Common/Firewall.php @@ -3,6 +3,7 @@ namespace Cleantalk\Common; use Cleantalk\ApbctWP\Variables\Cookie; +use Cleantalk\ApbctWP\Variables\Server; use Cleantalk\Common\Firewall\FirewallModule; use Cleantalk\ApbctWP\Variables\Get; @@ -26,6 +27,11 @@ class Firewall { public $ip_array = array(); + /** + * @var array example array ( 'ua', 'ua_id', 'ua_status') + */ + public $user_agent_data = array(); + // Database protected $db; @@ -64,6 +70,7 @@ public function __construct($db) $this->db = $db; $this->debug = (bool)Get::get('debug'); $this->ip_array = $this->ipGet(); + $this->user_agent_data = $this->getUserAgentData(); } /** @@ -81,6 +88,42 @@ public function ipGet($ips_input = 'real', $v4_only = true) return ! empty($result) ? array('real' => $result) : array(); } + public function getUserAgentData() + { + $server_ua = Server::getString('HTTP_USER_AGENT'); + $ua_table = defined('APBCT_TBL_AC_UA_BL') ? APBCT_TBL_AC_UA_BL : null; + + if ( $ua_table ) { + $ua_bl_query = "SELECT * FROM $ua_table ORDER BY `ua_status` DESC;"; + $ua_bl_results = $this->db->fetchAll($ua_bl_query); + foreach ( $ua_bl_results as $ua_bl_result ) { + if ( ! empty($ua_bl_result['ua_template']) ) { + $pattern = '%' . str_replace(array('"', '%'), array('', '\%'), $ua_bl_result['ua_template']) . '%i'; + $match = preg_match($pattern, $server_ua); + + if ( $match === false && in_array(preg_last_error(), array(PREG_BACKTRACK_LIMIT_ERROR, PREG_RECURSION_LIMIT_ERROR), true) ) { + continue; + } + + if ( $match === 1 ) { + $ua_id = TT::getArrayValueAsString($ua_bl_result, 'id'); + + return array( + 'ua' => $server_ua, + 'ua_id' => $ua_id, + 'ua_status' => TT::getArrayValueAsString($ua_bl_result, 'ua_status'), + ); + } + } + } + } + return array( + 'ua' => $server_ua, + 'ua_id' => null, + 'ua_status' => null, + ); + } + /** * Loads the FireWall module to the array. * For inner usage only. @@ -90,11 +133,12 @@ public function ipGet($ips_input = 'real', $v4_only = true) */ public function loadFwModule(FirewallModule $module) { - if ( ! in_array($module, $this->fw_modules)) { + if ( ! in_array($module, $this->fw_modules) ) { $module->setDb($this->db); $module->ipAppendAdditional($this->ip_array); $this->fw_modules[$module->module_name] = $module; $module->setIpArray($this->ip_array); + $module->setUserAgentData($this->user_agent_data); } } @@ -120,8 +164,11 @@ public function run() $results[$module->module_name] = $module_results; } - if ($this->isWhitelisted($results)) { - // Break protection logic if it whitelisted or trusted network. + if ( + $this->isWhitelisted($results) && + ( ! isset($this->user_agent_data['ua_status']) || (int) $this->user_agent_data['ua_status'] !== 0 ) + ) { + // Break protection logic if it whitelisted, or trusted network, or user-agent not blocked. break; } } diff --git a/lib/Cleantalk/Common/Firewall/FirewallModule.php b/lib/Cleantalk/Common/Firewall/FirewallModule.php index 0734cb7db..fdd49459d 100644 --- a/lib/Cleantalk/Common/Firewall/FirewallModule.php +++ b/lib/Cleantalk/Common/Firewall/FirewallModule.php @@ -79,6 +79,14 @@ public function setIpArray($ip_array) $this->ip_array = $ip_array; } + /** + * @param array $user_agent_data + */ + public function setUserAgentData($user_agent_data) + { + $this->user_agent_data = $user_agent_data; + } + /** * @param $result * diff --git a/lib/Cleantalk/Common/Firewall/FirewallModuleAbstract.php b/lib/Cleantalk/Common/Firewall/FirewallModuleAbstract.php index 11418da76..14024262a 100644 --- a/lib/Cleantalk/Common/Firewall/FirewallModuleAbstract.php +++ b/lib/Cleantalk/Common/Firewall/FirewallModuleAbstract.php @@ -40,6 +40,8 @@ abstract class FirewallModuleAbstract protected $ip_array = array(); + protected $user_agent_data = array(); + protected $test_ip; protected $passed_ip;