Spam protection, AntiSpam, FireWall by CleanTalk - Version 5.146.1

Version Description

Sep 23 2020 = * Fix: URL exclusions setting. * Fix: Login scripts output fixed. * Fix: Updater function name fixed. * New: Debug mode for Anti-Crawler. * Fix: Pass AC check if 301 HTTP response code received. * Fix: Antibot cookie value fixed.

Download this release

Release Info

Developer shagimuratov
Plugin Icon 128x128 Spam protection, AntiSpam, FireWall by CleanTalk
Version 5.146.1
Comparing to
See all releases

Code changes from version 5.146 to 5.146.1

cleantalk.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Anti-Spam by CleanTalk
4
  Plugin URI: https://cleantalk.org
5
  Description: Max power, all-in-one, no Captcha, premium anti-spam plugin. No comment spam, no registration spam, no contact spam, protects any WordPress forms.
6
- Version: 5.146
7
  Author: СleanTalk <welcome@cleantalk.org>
8
  Author URI: https://cleantalk.org
9
  Text Domain: cleantalk-spam-protect
3
  Plugin Name: Anti-Spam by CleanTalk
4
  Plugin URI: https://cleantalk.org
5
  Description: Max power, all-in-one, no Captcha, premium anti-spam plugin. No comment spam, no registration spam, no contact spam, protects any WordPress forms.
6
+ Version: 5.146.1
7
  Author: СleanTalk <welcome@cleantalk.org>
8
  Author URI: https://cleantalk.org
9
  Text Domain: cleantalk-spam-protect
inc/cleantalk-admin.php CHANGED
@@ -14,7 +14,7 @@ add_action( 'admin_head','apbct_admin_set_cookie_for_anti_bot' );
14
 
15
  function apbct_admin_set_cookie_for_anti_bot(){
16
  global $apbct;
17
- echo '<script>document.cookie = "apbct_antibot=' . md5( $apbct->api_key . \Cleantalk\ApbctWP\Helper::ip__get(array('real'), true ) ) . '; path=/; expires=0; samesite=lax";</script>';
18
  }
19
 
20
  function apbct_add_buttons_to_comments_and_users( $unused_argument ) {
14
 
15
  function apbct_admin_set_cookie_for_anti_bot(){
16
  global $apbct;
17
+ echo '<script>document.cookie = "apbct_antibot=' . hash( 'sha256', $apbct->api_key . $apbct->data['salt'] ) . '; path=/; expires=0; samesite=lax";</script>';
18
  }
19
 
20
  function apbct_add_buttons_to_comments_and_users( $unused_argument ) {
inc/cleantalk-common.php CHANGED
@@ -273,11 +273,11 @@ function apbct_exclusions_check__url() {
273
  // Fix for AJAX forms
274
  $haystack = apbct_get_server_variable( 'REQUEST_URI' ) == '/wp-admin/admin-ajax.php' && ! apbct_get_server_variable( 'HTTP_REFERER' )
275
  ? apbct_get_server_variable( 'HTTP_REFERER' )
276
- : apbct_get_server_variable( 'REQUEST_URI' );
277
-
278
  foreach ( $exclusions as $exclusion ) {
279
  if (
280
- ($apbct->settings['exclusions__urls__use_regexp'] && preg_match( '/' . $exclusion . '/', $haystack ) === 1) ||
281
  stripos( $haystack, $exclusion ) !== false
282
  ){
283
  return true;
273
  // Fix for AJAX forms
274
  $haystack = apbct_get_server_variable( 'REQUEST_URI' ) == '/wp-admin/admin-ajax.php' && ! apbct_get_server_variable( 'HTTP_REFERER' )
275
  ? apbct_get_server_variable( 'HTTP_REFERER' )
276
+ : \Cleantalk\Variables\Server::get('HTTP_HOST') . apbct_get_server_variable( 'REQUEST_URI' );
277
+
278
  foreach ( $exclusions as $exclusion ) {
279
  if (
280
+ ($apbct->settings['exclusions__urls__use_regexp'] && preg_match( '@' . $exclusion . '@', $haystack ) === 1) ||
281
  stripos( $haystack, $exclusion ) !== false
282
  ){
283
  return true;
inc/cleantalk-public.php CHANGED
@@ -1736,9 +1736,17 @@ function ct_register_form() {
1736
  }
1737
 
1738
  function apbct_login__scripts(){
1739
- global $apbct;
1740
- echo '<script src="'.APBCT_URL_PATH.'/js/apbct-public.min.js?ver="'. APBCT_VERSION .'></script>';
1741
- $apbct->public_script_loaded = true;
 
 
 
 
 
 
 
 
1742
  }
1743
 
1744
  /**
1736
  }
1737
 
1738
  function apbct_login__scripts(){
1739
+ global $apbct;
1740
+
1741
+ // Differnt JS params
1742
+ wp_enqueue_script( 'ct_public', APBCT_URL_PATH . '/js/apbct-public.min.js', array( 'jquery' ), APBCT_VERSION, false /*in header*/ );
1743
+
1744
+ wp_localize_script('ct_public', 'ctPublic', array(
1745
+ '_ajax_nonce' => wp_create_nonce('ct_secret_stuff'),
1746
+ '_ajax_url' => admin_url('admin-ajax.php'),
1747
+ ));
1748
+
1749
+ $apbct->public_script_loaded = true;
1750
  }
1751
 
1752
  /**
inc/cleantalk-settings.php CHANGED
@@ -1645,7 +1645,7 @@ function apbct_settings__sanitize__exclusions($exclusions, $regexp = false){
1645
  if( ! empty( $exclusions ) ){
1646
  $exclusions = explode( ',', $exclusions );
1647
  foreach ( $exclusions as $exclusion ){
1648
- $sanitized_exclusion = trim( $exclusion );
1649
  if ( ! empty( $sanitized_exclusion ) ) {
1650
  if( $regexp && ! apbct_is_regexp( $exclusion ) )
1651
  return false;
1645
  if( ! empty( $exclusions ) ){
1646
  $exclusions = explode( ',', $exclusions );
1647
  foreach ( $exclusions as $exclusion ){
1648
+ $sanitized_exclusion = trim( $exclusion, " \t\n\r\0\x0B/\/" );
1649
  if ( ! empty( $sanitized_exclusion ) ) {
1650
  if( $regexp && ! apbct_is_regexp( $exclusion ) )
1651
  return false;
inc/cleantalk-updater.php CHANGED
@@ -596,7 +596,7 @@ function apbct_update_to_5_143_2() {
596
 
597
  }
598
 
599
- function apbct_update_to_5_146() {
600
 
601
  global $apbct;
602
 
596
 
597
  }
598
 
599
+ function apbct_update_to_5_146_1() {
600
 
601
  global $apbct;
602
 
lib/Cleantalk/Antispam/Cleantalk.php CHANGED
@@ -1,542 +1,542 @@
1
- <?php
2
-
3
- namespace Cleantalk\Antispam;
4
-
5
- /**
6
- * Cleantalk base class
7
- *
8
- * @version 2.2
9
- * @package Cleantalk
10
- * @subpackage Base
11
- * @author Cleantalk team (welcome@cleantalk.org)
12
- * @copyright (C) 2014 CleanTalk team (http://cleantalk.org)
13
- * @license GNU/GPL: http://www.gnu.org/copyleft/gpl.html
14
- * @see https://github.com/CleanTalk/php-antispam
15
- *
16
- */
17
- class Cleantalk {
18
-
19
- /*
20
- * Use Wordpress built-in API
21
- */
22
- public $use_bultin_api = false;
23
-
24
- /**
25
- * Maximum data size in bytes
26
- * @var int
27
- */
28
- private $dataMaxSise = 32768;
29
-
30
- /**
31
- * Data compression rate
32
- * @var int
33
- */
34
- private $compressRate = 6;
35
-
36
- /**
37
- * Server connection timeout in seconds
38
- * @var int
39
- */
40
- private $server_timeout = 15;
41
-
42
- /**
43
- * Cleantalk server url
44
- * @var string
45
- */
46
- public $server_url = null;
47
-
48
- /**
49
- * Last work url
50
- * @var string
51
- */
52
- public $work_url = null;
53
-
54
- /**
55
- * WOrk url ttl
56
- * @var int
57
- */
58
- public $server_ttl = null;
59
-
60
- /**
61
- * Time wotk_url changer
62
- * @var int
63
- */
64
- public $server_changed = null;
65
-
66
- /**
67
- * Flag is change server url
68
- * @var bool
69
- */
70
- public $server_change = false;
71
-
72
- /**
73
- * Codepage of the data
74
- * @var bool
75
- */
76
- public $data_codepage = null;
77
-
78
- /**
79
- * API version to use
80
- * @var string
81
- */
82
- public $api_version = '/api2.0';
83
-
84
- /**
85
- * Use https connection to servers
86
- * @var bool
87
- */
88
- public $ssl_on = false;
89
-
90
- /**
91
- * Path to SSL certificate
92
- * @var string
93
- */
94
- public $ssl_path = '';
95
-
96
- /**
97
- * Minimal server response in miliseconds to catch the server
98
- *
99
- */
100
- public $min_server_timeout = 50;
101
-
102
- /**
103
- * Maximal server response in miliseconds to catch the server
104
- *
105
- */
106
- public $max_server_timeout = 1500;
107
-
108
- /**
109
- * Function checks whether it is possible to publish the message
110
- *
111
- * @param CleantalkRequest $request
112
- *
113
- * @return bool|CleantalkResponse
114
- */
115
- public function isAllowMessage(CleantalkRequest $request) {
116
- $msg = $this->createMsg('check_message', $request);
117
- return $this->httpRequest($msg);
118
- }
119
-
120
- /**
121
- * Function checks whether it is possible to publish the message
122
- *
123
- * @param CleantalkRequest $request
124
- *
125
- * @return bool|CleantalkResponse
126
- */
127
- public function isAllowUser(CleantalkRequest $request) {
128
- $msg = $this->createMsg('check_newuser', $request);
129
- return $this->httpRequest($msg);
130
- }
131
-
132
- /**
133
- * Function sends the results of manual moderation
134
- *
135
- * @param CleantalkRequest $request
136
- *
137
- * @return bool|CleantalkResponse
138
- */
139
- public function sendFeedback(CleantalkRequest $request) {
140
- $msg = $this->createMsg('send_feedback', $request);
141
- return $this->httpRequest($msg);
142
- }
143
-
144
- /**
145
- * Create msg for cleantalk server
146
- * @param string $method
147
- * @param CleantalkRequest $request
148
- * @return CleantalkRequest
149
- */
150
- private function createMsg($method, CleantalkRequest $request) {
151
-
152
- switch ($method) {
153
- case 'check_message':
154
- // Convert strings to UTF8
155
- $request->message = \Cleantalk\ApbctWP\Helper::toUTF8($request->message, $this->data_codepage);
156
- $request->example = \Cleantalk\ApbctWP\Helper::toUTF8($request->example, $this->data_codepage);
157
- $request->sender_email = \Cleantalk\ApbctWP\Helper::toUTF8($request->sender_email, $this->data_codepage);
158
- $request->sender_nickname = \Cleantalk\ApbctWP\Helper::toUTF8($request->sender_nickname, $this->data_codepage);
159
- $request->message = $this->compressData($request->message);
160
- $request->example = $this->compressData($request->example);
161
- break;
162
-
163
- case 'check_newuser':
164
- // Convert strings to UTF8
165
- $request->sender_email = \Cleantalk\ApbctWP\Helper::toUTF8($request->sender_email, $this->data_codepage);
166
- $request->sender_nickname = \Cleantalk\ApbctWP\Helper::toUTF8($request->sender_nickname, $this->data_codepage);
167
- break;
168
-
169
- case 'send_feedback':
170
- if (is_array($request->feedback)) {
171
- $request->feedback = implode(';', $request->feedback);
172
- }
173
- break;
174
- }
175
-
176
- // Removing non UTF8 characters from request, because non UTF8 or malformed characters break json_encode().
177
- foreach ($request as $param => $value) {
178
- if(is_array($request->$param) || is_string($request->$param))
179
- $request->$param = \Cleantalk\ApbctWP\Helper::removeNonUTF8($value);
180
- }
181
-
182
- $request->method_name = $method;
183
- $request->message = is_array($request->message) ? json_encode($request->message) : $request->message;
184
-
185
- // Wiping cleantalk's headers but, not for send_feedback
186
- if($request->method_name != 'send_feedback'){
187
-
188
- $ct_tmp = apache_request_headers();
189
-
190
- if(isset($ct_tmp['Cookie']))
191
- $cookie_name = 'Cookie';
192
- elseif(isset($ct_tmp['cookie']))
193
- $cookie_name = 'cookie';
194
- else
195
- $cookie_name = 'COOKIE';
196
-
197
- $ct_tmp[$cookie_name] = preg_replace(array(
198
- '/\s?ct_checkjs=[a-z0-9]*[^;]*;?/',
199
- '/\s?ct_timezone=.{0,1}\d{1,2}[^;]*;?/',
200
- '/\s?ct_pointer_data=.*5D[^;]*;?/',
201
- '/\s?apbct_timestamp=\d*[^;]*;?/',
202
- '/\s?apbct_site_landing_ts=\d*[^;]*;?/',
203
- '/\s?apbct_cookies_test=%7B.*%7D[^;]*;?/',
204
- '/\s?apbct_prev_referer=http.*?[^;]*;?/',
205
- '/\s?ct_cookies_test=.*?[^;]*;?/',
206
- '/\s?ct_ps_timestamp=.*?[^;]*;?/',
207
- '/\s?ct_fkp_timestamp=\d*?[^;]*;?/',
208
- '/\s?ct_sfw_pass_key=\d*?[^;]*;?/',
209
- '/\s?apbct_page_hits=\d*?[^;]*;?/',
210
- '/\s?apbct_visible_fields_count=\d*?[^;]*;?/',
211
- '/\s?apbct_visible_fields=%7B.*%7D[^;]*;?/',
212
- ), '', $ct_tmp[$cookie_name]);
213
- $request->all_headers = json_encode($ct_tmp);
214
- }
215
-
216
- return $request;
217
- }
218
-
219
- /**
220
- * Compress data and encode to base64
221
- * @param type string
222
- * @return string
223
- */
224
- private function compressData($data = null){
225
-
226
- if (strlen($data) > $this->dataMaxSise && function_exists('\gzencode') && function_exists('base64_encode')){
227
-
228
- $localData = \gzencode($data, $this->compressRate, FORCE_GZIP);
229
-
230
- if ($localData === false)
231
- return $data;
232
-
233
- $localData = base64_encode($localData);
234
-
235
- if ($localData === false)
236
- return $data;
237
-
238
- return $localData;
239
- }
240
-
241
- return $data;
242
- }
243
-
244
- /**
245
- * httpRequest
246
- * @param $msg
247
- * @return boolean|\CleantalkResponse
248
- */
249
- private function httpRequest($msg) {
250
-
251
- // Using current server without changing it
252
- $result = !empty($this->work_url) && ($this->server_changed + $this->server_ttl > time())
253
- ? $this->sendRequest($msg, $this->work_url, $this->server_timeout)
254
- : false;
255
-
256
- // Changing server
257
- if ($result === false || (is_object($result) && $result->errno != 0)) {
258
-
259
- // Split server url to parts
260
- preg_match("/^(https?:\/\/)([^\/:]+)(.*)/i", $this->server_url, $matches);
261
-
262
- $url_protocol = isset($matches[1]) ? $matches[1] : '';
263
- $url_host = isset($matches[2]) ? $matches[2] : '';
264
- $url_suffix = isset($matches[3]) ? $matches[3] : '';
265
-
266
- $servers = $this->get_servers_ip($url_host);
267
-
268
- // Loop until find work server
269
- foreach ($servers as $server) {
270
-
271
- $dns = \Cleantalk\ApbctWP\Helper::ip__resolve__cleantalks($server['ip']);
272
- if(!$dns)
273
- continue;
274
-
275
- $this->work_url = $url_protocol.$dns.$url_suffix;
276
- $this->server_ttl = $server['ttl'];
277
-
278
- $result = $this->sendRequest($msg, $this->work_url, $this->server_timeout);
279
-
280
- if ($result !== false && $result->errno === 0) {
281
- $this->server_change = true;
282
- break;
283
- }
284
- }
285
- }
286
-
287
- $response = new CleantalkResponse(null, $result);
288
-
289
- if (!empty($this->data_codepage) && $this->data_codepage !== 'UTF-8') {
290
- if (!empty($response->comment))
291
- $response->comment = $this->stringFromUTF8($response->comment, $this->data_codepage);
292
- if (!empty($response->errstr))
293
- $response->errstr = $this->stringFromUTF8($response->errstr, $this->data_codepage);
294
- if (!empty($response->sms_error_text))
295
- $response->sms_error_text = $this->stringFromUTF8($response->sms_error_text, $this->data_codepage);
296
- }
297
-
298
- return $response;
299
- }
300
-
301
- /**
302
- * Function DNS request
303
- * @param $host
304
- * @return array
305
- */
306
- public function get_servers_ip($host)
307
- {
308
- if (!isset($host))
309
- return null;
310
-
311
- $servers = array();
312
-
313
- // Get DNS records about URL
314
- if (function_exists('dns_get_record')) {
315
- $records = dns_get_record($host, DNS_A);
316
- if ($records !== FALSE) {
317
- foreach ($records as $server) {
318
- $servers[] = $server;
319
- }
320
- }
321
- }
322
-
323
- // Another try if first failed
324
- if (count($servers) == 0 && function_exists('gethostbynamel')) {
325
- $records = gethostbynamel($host);
326
- if ($records !== FALSE) {
327
- foreach ($records as $server) {
328
- $servers[] = array(
329
- "ip" => $server,
330
- "host" => $host,
331
- "ttl" => $this->server_ttl
332
- );
333
- }
334
- }
335
- }
336
-
337
- // If couldn't get records
338
- if (count($servers) == 0){
339
-
340
- $servers[] = array(
341
- "ip" => null,
342
- "host" => $host,
343
- "ttl" => $this->server_ttl
344
- );
345
-
346
- // If records recieved
347
- } else {
348
-
349
- $tmp = null;
350
- $fast_server_found = false;
351
-
352
- foreach ($servers as $server) {
353
-
354
- if ($fast_server_found) {
355
- $ping = $this->max_server_timeout;
356
- } else {
357
- $ping = $this->httpPing($server['ip']);
358
- $ping = $ping * 1000;
359
- }
360
-
361
- $tmp[$ping] = $server;
362
-
363
- $fast_server_found = $ping < $this->min_server_timeout ? true : false;
364
-
365
- }
366
-
367
- if (count($tmp)){
368
- ksort($tmp);
369
- $response = $tmp;
370
- }
371
-
372
- }
373
-
374
- return empty($response) ? null : $response;
375
- }
376
-
377
- /**
378
- * Function to check response time
379
- * param string
380
- * @return int
381
- */
382
- function httpPing($host){
383
-
384
- // Skip localhost ping cause it raise error at fsockopen.
385
- // And return minimun value
386
- if ($host == 'localhost')
387
- return 0.001;
388
-
389
- $starttime = microtime(true);
390
- $file = @fsockopen ($host, 80, $errno, $errstr, $this->max_server_timeout/1000);
391
- $stoptime = microtime(true);
392
-
393
- if (!$file) {
394
- $status = $this->max_server_timeout/1000; // Site is down
395
- } else {
396
- fclose($file);
397
- $status = ($stoptime - $starttime);
398
- $status = round($status, 4);
399
- }
400
-
401
- return $status;
402
- }
403
-
404
- /**
405
- * Send JSON request to servers
406
- * @param $msg
407
- * @return boolean|\CleantalkResponse
408
- */
409
- private function sendRequest($data = null, $url, $server_timeout = 3)
410
- {
411
- $original_args = func_get_args();
412
- // Convert to array
413
- $data = (array)json_decode(json_encode($data), true);
414
-
415
- //Cleaning from 'null' values
416
- $tmp_data = array();
417
- foreach($data as $key => $value){
418
- if($value !== null)
419
- $tmp_data[$key] = $value;
420
- }
421
- $data = $tmp_data;
422
- unset($key, $value, $tmp_data);
423
-
424
- // Convert to JSON
425
- $data = json_encode($data);
426
-
427
- if (isset($this->api_version)) {
428
- $url = $url . $this->api_version;
429
- }
430
-
431
- $result = false;
432
- $curl_error = null;
433
-
434
- // Switching to secure connection
435
- if ($this->ssl_on && !preg_match("/^https:/", $url)){
436
- $url = preg_replace("/^(http)/i", "$1s", $url);
437
- }
438
-
439
- if($this->use_bultin_api){
440
-
441
- $args = array(
442
- 'body' => $data,
443
- 'timeout' => $server_timeout,
444
- 'user-agent' => APBCT_AGENT.' '.get_bloginfo( 'url' ),
445
- );
446
-
447
- $result = wp_remote_post($url, $args);
448
-
449
- if( is_wp_error( $result ) ) {
450
- $errors = $result->get_error_message();
451
- $result = false;
452
- }else{
453
- $result = wp_remote_retrieve_body($result);
454
- }
455
-
456
- }else{
457
-
458
- if(function_exists('curl_init')) {
459
-
460
- $ch = curl_init();
461
-
462
- curl_setopt($ch, CURLOPT_URL, $url);
463
- curl_setopt($ch, CURLOPT_TIMEOUT, $server_timeout);
464
- curl_setopt($ch, CURLOPT_POST, 1);
465
- curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
466
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // receive server response ...
467
- curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:')); // resolve 'Expect: 100-continue' issue
468
- curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); // see http://stackoverflow.com/a/23322368
469
-
470
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // Disabling CA cert verivication and
471
- curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); // Disabling common name verification
472
-
473
- if ($this->ssl_on && $this->ssl_path != '') {
474
- curl_setopt($ch, CURLOPT_CAINFO, $this->ssl_path);
475
- }
476
-
477
- $result = curl_exec($ch);
478
- if (!$result) {
479
- $curl_error = curl_error($ch);
480
- // Use SSL next time, if error occurs.
481
- if(!$this->ssl_on){
482
- $this->ssl_on = true;
483
- return $this->sendRequest($original_args[0], $original_args[1], $server_timeout);
484
- }
485
- }
486
-
487
- curl_close($ch);
488
- }
489
- }
490
-
491
- if (!$result) {
492
- $allow_url_fopen = ini_get('allow_url_fopen');
493
- if (function_exists('file_get_contents') && isset($allow_url_fopen) && $allow_url_fopen == '1') {
494
- $opts = array('http' =>
495
- array(
496
- 'method' => 'POST',
497
- 'header' => "Content-Type: text/html\r\n",
498
- 'content' => $data,
499
- 'timeout' => $server_timeout
500
- )
501
- );
502
-
503
- $context = stream_context_create($opts);
504
- $result = @file_get_contents($url, false, $context);
505
- }
506
- }
507
-
508
- if (!$result) {
509
- $response = null;
510
- $response['errno'] = 2;
511
- if (!\Cleantalk\ApbctWP\Helper::is_json($result)) {
512
- $response['errstr'] = 'Wrong server response format: ' . substr( $result, 100 );
513
- }
514
- else {
515
- $response['errstr'] = $curl_error
516
- ? sprintf( "CURL error: '%s'", $curl_error )
517
- : 'No CURL support compiled in';
518
- $response['errstr'] .= ' or disabled allow_url_fopen in php.ini.';
519
- }
520
- $response = json_decode( json_encode( $response ) );
521
-
522
- return $response;
523
- }
524
-
525
- $errstr = null;
526
- $response = json_decode($result);
527
- if ($result !== false && is_object($response)) {
528
- $response->errno = 0;
529
- $response->errstr = $errstr;
530
- } else {
531
- $errstr = 'Unknown response from ' . $url . '.' . ' ' . $result;
532
-
533
- $response = null;
534
- $response['errno'] = 1;
535
- $response['errstr'] = $errstr;
536
- $response = json_decode(json_encode($response));
537
- }
538
-
539
-
540
- return $response;
541
- }
542
- }
1
+ <?php
2
+
3
+ namespace Cleantalk\Antispam;
4
+
5
+ /**
6
+ * Cleantalk base class
7
+ *
8
+ * @version 2.2
9
+ * @package Cleantalk
10
+ * @subpackage Base
11
+ * @author Cleantalk team (welcome@cleantalk.org)
12
+ * @copyright (C) 2014 CleanTalk team (http://cleantalk.org)
13
+ * @license GNU/GPL: http://www.gnu.org/copyleft/gpl.html
14
+ * @see https://github.com/CleanTalk/php-antispam
15
+ *
16
+ */
17
+ class Cleantalk {
18
+
19
+ /*
20
+ * Use Wordpress built-in API
21
+ */
22
+ public $use_bultin_api = false;
23
+
24
+ /**
25
+ * Maximum data size in bytes
26
+ * @var int
27
+ */
28
+ private $dataMaxSise = 32768;
29
+
30
+ /**
31
+ * Data compression rate
32
+ * @var int
33
+ */
34
+ private $compressRate = 6;
35
+
36
+ /**
37
+ * Server connection timeout in seconds
38
+ * @var int
39
+ */
40
+ private $server_timeout = 15;
41
+
42
+ /**
43
+ * Cleantalk server url
44
+ * @var string
45
+ */
46
+ public $server_url = null;
47
+
48
+ /**
49
+ * Last work url
50
+ * @var string
51
+ */
52
+ public $work_url = null;
53
+
54
+ /**
55
+ * WOrk url ttl
56
+ * @var int
57
+ */
58
+ public $server_ttl = null;
59
+
60
+ /**
61
+ * Time wotk_url changer
62
+ * @var int
63
+ */
64
+ public $server_changed = null;
65
+
66
+ /**
67
+ * Flag is change server url
68
+ * @var bool
69
+ */
70
+ public $server_change = false;
71
+
72
+ /**
73
+ * Codepage of the data
74
+ * @var bool
75
+ */
76
+ public $data_codepage = null;
77
+
78
+ /**
79
+ * API version to use
80
+ * @var string
81
+ */
82
+ public $api_version = '/api2.0';
83
+
84
+ /**
85
+ * Use https connection to servers
86
+ * @var bool
87
+ */
88
+ public $ssl_on = false;
89
+
90
+ /**
91
+ * Path to SSL certificate
92
+ * @var string
93
+ */
94
+ public $ssl_path = '';
95
+
96
+ /**
97
+ * Minimal server response in miliseconds to catch the server
98
+ *
99
+ */
100
+ public $min_server_timeout = 50;
101
+
102
+ /**
103
+ * Maximal server response in miliseconds to catch the server
104
+ *
105
+ */
106
+ public $max_server_timeout = 1500;
107
+
108
+ /**
109
+ * Function checks whether it is possible to publish the message
110
+ *
111
+ * @param CleantalkRequest $request
112
+ *
113
+ * @return bool|CleantalkResponse
114
+ */
115
+ public function isAllowMessage(CleantalkRequest $request) {
116
+ $msg = $this->createMsg('check_message', $request);
117
+ return $this->httpRequest($msg);
118
+ }
119
+
120
+ /**
121
+ * Function checks whether it is possible to publish the message
122
+ *
123
+ * @param CleantalkRequest $request
124
+ *
125
+ * @return bool|CleantalkResponse
126
+ */
127
+ public function isAllowUser(CleantalkRequest $request) {
128
+ $msg = $this->createMsg('check_newuser', $request);
129
+ return $this->httpRequest($msg);
130
+ }
131
+
132
+ /**
133
+ * Function sends the results of manual moderation
134
+ *
135
+ * @param CleantalkRequest $request
136
+ *
137
+ * @return bool|CleantalkResponse
138
+ */
139
+ public function sendFeedback(CleantalkRequest $request) {
140
+ $msg = $this->createMsg('send_feedback', $request);
141
+ return $this->httpRequest($msg);
142
+ }
143
+
144
+ /**
145
+ * Create msg for cleantalk server
146
+ * @param string $method
147
+ * @param CleantalkRequest $request
148
+ * @return CleantalkRequest
149
+ */
150
+ private function createMsg($method, CleantalkRequest $request) {
151
+
152
+ switch ($method) {
153
+ case 'check_message':
154
+ // Convert strings to UTF8
155
+ $request->message = \Cleantalk\ApbctWP\Helper::toUTF8($request->message, $this->data_codepage);
156
+ $request->example = \Cleantalk\ApbctWP\Helper::toUTF8($request->example, $this->data_codepage);
157
+ $request->sender_email = \Cleantalk\ApbctWP\Helper::toUTF8($request->sender_email, $this->data_codepage);
158
+ $request->sender_nickname = \Cleantalk\ApbctWP\Helper::toUTF8($request->sender_nickname, $this->data_codepage);
159
+ $request->message = $this->compressData($request->message);
160
+ $request->example = $this->compressData($request->example);
161
+ break;
162
+
163
+ case 'check_newuser':
164
+ // Convert strings to UTF8
165
+ $request->sender_email = \Cleantalk\ApbctWP\Helper::toUTF8($request->sender_email, $this->data_codepage);
166
+ $request->sender_nickname = \Cleantalk\ApbctWP\Helper::toUTF8($request->sender_nickname, $this->data_codepage);
167
+ break;
168
+
169
+ case 'send_feedback':
170
+ if (is_array($request->feedback)) {
171
+ $request->feedback = implode(';', $request->feedback);
172
+ }
173
+ break;
174
+ }
175
+
176
+ // Removing non UTF8 characters from request, because non UTF8 or malformed characters break json_encode().
177
+ foreach ($request as $param => $value) {
178
+ if(is_array($request->$param) || is_string($request->$param))
179
+ $request->$param = \Cleantalk\ApbctWP\Helper::removeNonUTF8($value);
180
+ }
181
+
182
+ $request->method_name = $method;
183
+ $request->message = is_array($request->message) ? json_encode($request->message) : $request->message;
184
+
185
+ // Wiping cleantalk's headers but, not for send_feedback
186
+ if($request->method_name != 'send_feedback'){
187
+
188
+ $ct_tmp = apache_request_headers();
189
+
190
+ if(isset($ct_tmp['Cookie']))
191
+ $cookie_name = 'Cookie';
192
+ elseif(isset($ct_tmp['cookie']))
193
+ $cookie_name = 'cookie';
194
+ else
195
+ $cookie_name = 'COOKIE';
196
+
197
+ $ct_tmp[$cookie_name] = preg_replace(array(
198
+ '/\s?ct_checkjs=[a-z0-9]*[^;]*;?/',
199
+ '/\s?ct_timezone=.{0,1}\d{1,2}[^;]*;?/',
200
+ '/\s?ct_pointer_data=.*5D[^;]*;?/',
201
+ '/\s?apbct_timestamp=\d*[^;]*;?/',
202
+ '/\s?apbct_site_landing_ts=\d*[^;]*;?/',
203
+ '/\s?apbct_cookies_test=%7B.*%7D[^;]*;?/',
204
+ '/\s?apbct_prev_referer=http.*?[^;]*;?/',
205
+ '/\s?ct_cookies_test=.*?[^;]*;?/',
206
+ '/\s?ct_ps_timestamp=.*?[^;]*;?/',
207
+ '/\s?ct_fkp_timestamp=\d*?[^;]*;?/',
208
+ '/\s?ct_sfw_pass_key=\d*?[^;]*;?/',
209
+ '/\s?apbct_page_hits=\d*?[^;]*;?/',
210
+ '/\s?apbct_visible_fields_count=\d*?[^;]*;?/',
211
+ '/\s?apbct_visible_fields=%7B.*%7D[^;]*;?/',
212
+ ), '', $ct_tmp[$cookie_name]);
213
+ $request->all_headers = json_encode($ct_tmp);
214
+ }
215
+
216
+ return $request;
217
+ }
218
+
219
+ /**
220
+ * Compress data and encode to base64
221
+ * @param type string
222
+ * @return string
223
+ */
224
+ private function compressData($data = null){
225
+
226
+ if (strlen($data) > $this->dataMaxSise && function_exists('\gzencode') && function_exists('base64_encode')){
227
+
228
+ $localData = \gzencode($data, $this->compressRate, FORCE_GZIP);
229
+
230
+ if ($localData === false)
231
+ return $data;
232
+
233
+ $localData = base64_encode($localData);
234
+
235
+ if ($localData === false)
236
+ return $data;
237
+
238
+ return $localData;
239
+ }
240
+
241
+ return $data;
242
+ }
243
+
244
+ /**
245
+ * httpRequest
246
+ * @param $msg
247
+ * @return boolean|\CleantalkResponse
248
+ */
249
+ private function httpRequest($msg) {
250
+
251
+ // Using current server without changing it
252
+ $result = !empty($this->work_url) && ($this->server_changed + $this->server_ttl > time())
253
+ ? $this->sendRequest($msg, $this->work_url, $this->server_timeout)
254
+ : false;
255
+
256
+ // Changing server
257
+ if ($result === false || (is_object($result) && $result->errno != 0)) {
258
+
259
+ // Split server url to parts
260
+ preg_match("/^(https?:\/\/)([^\/:]+)(.*)/i", $this->server_url, $matches);
261
+
262
+ $url_protocol = isset($matches[1]) ? $matches[1] : '';
263
+ $url_host = isset($matches[2]) ? $matches[2] : '';
264
+ $url_suffix = isset($matches[3]) ? $matches[3] : '';
265
+
266
+ $servers = $this->get_servers_ip($url_host);
267
+
268
+ // Loop until find work server
269
+ foreach ($servers as $server) {
270
+
271
+ $dns = \Cleantalk\ApbctWP\Helper::ip__resolve__cleantalks($server['ip']);
272
+ if(!$dns)
273
+ continue;
274
+
275
+ $this->work_url = $url_protocol.$dns.$url_suffix;
276
+ $this->server_ttl = $server['ttl'];
277
+
278
+ $result = $this->sendRequest($msg, $this->work_url, $this->server_timeout);
279
+
280
+ if ($result !== false && $result->errno === 0) {
281
+ $this->server_change = true;
282
+ break;
283
+ }
284
+ }
285
+ }
286
+
287
+ $response = new CleantalkResponse(null, $result);
288
+
289
+ if (!empty($this->data_codepage) && $this->data_codepage !== 'UTF-8') {
290
+ if (!empty($response->comment))
291
+ $response->comment = $this->stringFromUTF8($response->comment, $this->data_codepage);
292
+ if (!empty($response->errstr))
293
+ $response->errstr = $this->stringFromUTF8($response->errstr, $this->data_codepage);
294
+ if (!empty($response->sms_error_text))
295
+ $response->sms_error_text = $this->stringFromUTF8($response->sms_error_text, $this->data_codepage);
296
+ }
297
+
298
+ return $response;
299
+ }
300
+
301
+ /**
302
+ * Function DNS request
303
+ * @param $host
304
+ * @return array
305
+ */
306
+ public function get_servers_ip($host)
307
+ {
308
+ if (!isset($host))
309
+ return null;
310
+
311
+ $servers = array();
312
+
313
+ // Get DNS records about URL
314
+ if (function_exists('dns_get_record')) {
315
+ $records = dns_get_record($host, DNS_A);
316
+ if ($records !== FALSE) {
317
+ foreach ($records as $server) {
318
+ $servers[] = $server;
319
+ }
320
+ }
321
+ }
322
+
323
+ // Another try if first failed
324
+ if (count($servers) == 0 && function_exists('gethostbynamel')) {
325
+ $records = gethostbynamel($host);
326
+ if ($records !== FALSE) {
327
+ foreach ($records as $server) {
328
+ $servers[] = array(
329
+ "ip" => $server,
330
+ "host" => $host,
331
+ "ttl" => $this->server_ttl
332
+ );
333
+ }
334
+ }
335
+ }
336
+
337
+ // If couldn't get records
338
+ if (count($servers) == 0){
339
+
340
+ $servers[] = array(
341
+ "ip" => null,
342
+ "host" => $host,
343
+ "ttl" => $this->server_ttl
344
+ );
345
+
346
+ // If records recieved
347
+ } else {
348
+
349
+ $tmp = null;
350
+ $fast_server_found = false;
351
+
352
+ foreach ($servers as $server) {
353
+
354
+ if ($fast_server_found) {
355
+ $ping = $this->max_server_timeout;
356
+ } else {
357
+ $ping = $this->httpPing($server['ip']);
358
+ $ping = $ping * 1000;
359
+ }
360
+
361
+ $tmp[$ping] = $server;
362
+
363
+ $fast_server_found = $ping < $this->min_server_timeout ? true : false;
364
+
365
+ }
366
+
367
+ if (count($tmp)){
368
+ ksort($tmp);
369
+ $response = $tmp;
370
+ }
371
+
372
+ }
373
+
374
+ return empty($response) ? null : $response;
375
+ }
376
+
377
+ /**
378
+ * Function to check response time
379
+ * param string
380
+ * @return int
381
+ */
382
+ function httpPing($host){
383
+
384
+ // Skip localhost ping cause it raise error at fsockopen.
385
+ // And return minimun value
386
+ if ($host == 'localhost')
387
+ return 0.001;
388
+
389
+ $starttime = microtime(true);
390
+ $file = @fsockopen ($host, 80, $errno, $errstr, $this->max_server_timeout/1000);
391
+ $stoptime = microtime(true);
392
+
393
+ if (!$file) {
394
+ $status = $this->max_server_timeout/1000; // Site is down
395
+ } else {
396
+ fclose($file);
397
+ $status = ($stoptime - $starttime);
398
+ $status = round($status, 4);
399
+ }
400
+
401
+ return $status;
402
+ }
403
+
404
+ /**
405
+ * Send JSON request to servers
406
+ * @param $msg
407
+ * @return boolean|\CleantalkResponse
408
+ */
409
+ private function sendRequest($data = null, $url, $server_timeout = 3)
410
+ {
411
+ $original_args = func_get_args();
412
+ // Convert to array
413
+ $data = (array)json_decode(json_encode($data), true);
414
+
415
+ //Cleaning from 'null' values
416
+ $tmp_data = array();
417
+ foreach($data as $key => $value){
418
+ if($value !== null)
419
+ $tmp_data[$key] = $value;
420
+ }
421
+ $data = $tmp_data;
422
+ unset($key, $value, $tmp_data);
423
+
424
+ // Convert to JSON
425
+ $data = json_encode($data);
426
+
427
+ if (isset($this->api_version)) {
428
+ $url = $url . $this->api_version;
429
+ }
430
+
431
+ $result = false;
432
+ $curl_error = null;
433
+
434
+ // Switching to secure connection
435
+ if ($this->ssl_on && !preg_match("/^https:/", $url)){
436
+ $url = preg_replace("/^(http)/i", "$1s", $url);
437
+ }
438
+
439
+ if($this->use_bultin_api){
440
+
441
+ $args = array(
442
+ 'body' => $data,
443
+ 'timeout' => $server_timeout,
444
+ 'user-agent' => APBCT_AGENT.' '.get_bloginfo( 'url' ),
445
+ );
446
+
447
+ $result = wp_remote_post($url, $args);
448
+
449
+ if( is_wp_error( $result ) ) {
450
+ $errors = $result->get_error_message();
451
+ $result = false;
452
+ }else{
453
+ $result = wp_remote_retrieve_body($result);
454
+ }
455
+
456
+ }else{
457
+
458
+ if(function_exists('curl_init')) {
459
+
460
+ $ch = curl_init();
461
+
462
+ curl_setopt($ch, CURLOPT_URL, $url);
463
+ curl_setopt($ch, CURLOPT_TIMEOUT, $server_timeout);
464
+ curl_setopt($ch, CURLOPT_POST, 1);
465
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
466
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // receive server response ...
467
+ curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:')); // resolve 'Expect: 100-continue' issue
468
+ curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); // see http://stackoverflow.com/a/23322368
469
+
470
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // Disabling CA cert verivication and
471
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); // Disabling common name verification
472
+
473
+ if ($this->ssl_on && $this->ssl_path != '') {
474
+ curl_setopt($ch, CURLOPT_CAINFO, $this->ssl_path);
475
+ }
476
+
477
+ $result = curl_exec($ch);
478
+ if (!$result) {
479
+ $curl_error = curl_error($ch);
480
+ // Use SSL next time, if error occurs.
481
+ if(!$this->ssl_on){
482
+ $this->ssl_on = true;
483
+ return $this->sendRequest($original_args[0], $original_args[1], $server_timeout);
484
+ }
485
+ }
486
+
487
+ curl_close($ch);
488
+ }
489
+ }
490
+
491
+ if (!$result) {
492
+ $allow_url_fopen = ini_get('allow_url_fopen');
493
+ if (function_exists('file_get_contents') && isset($allow_url_fopen) && $allow_url_fopen == '1') {
494
+ $opts = array('http' =>
495
+ array(
496
+ 'method' => 'POST',
497
+ 'header' => "Content-Type: text/html\r\n",
498
+ 'content' => $data,
499
+ 'timeout' => $server_timeout
500
+ )
501
+ );
502
+
503
+ $context = stream_context_create($opts);
504
+ $result = @file_get_contents($url, false, $context);
505
+ }
506
+ }
507
+
508
+ if (!$result) {
509
+ $response = null;
510
+ $response['errno'] = 2;
511
+ if (!\Cleantalk\ApbctWP\Helper::is_json($result)) {
512
+ $response['errstr'] = 'Wrong server response format: ' . substr( $result, 100 );
513
+ }
514
+ else {
515
+ $response['errstr'] = $curl_error
516
+ ? sprintf( "CURL error: '%s'", $curl_error )
517
+ : 'No CURL support compiled in';
518
+ $response['errstr'] .= ' or disabled allow_url_fopen in php.ini.';
519
+ }
520
+ $response = json_decode( json_encode( $response ) );
521
+
522
+ return $response;
523
+ }
524
+
525
+ $errstr = null;
526
+ $response = json_decode($result);
527
+ if ($result !== false && is_object($response)) {
528
+ $response->errno = 0;
529
+ $response->errstr = $errstr;
530
+ } else {
531
+ $errstr = 'Unknown response from ' . $url . '.' . ' ' . $result;
532
+
533
+ $response = null;
534
+ $response['errno'] = 1;
535
+ $response['errstr'] = $errstr;
536
+ $response = json_decode(json_encode($response));
537
+ }
538
+
539
+
540
+ return $response;
541
+ }
542
+ }
lib/Cleantalk/ApbctWP/Firewall/AntiCrawler.php CHANGED
@@ -10,12 +10,14 @@ class AntiCrawler extends \Cleantalk\Common\Firewall\FirewallModule{
10
 
11
  public $module_name = 'ANTICRAWLER';
12
 
13
- private $db__table__ac_logs;
14
  private $api_key = '';
15
  private $apbct = false;
16
  private $store_interval = 60;
17
  private $ua; //User-Agent
18
-
 
 
19
  public $isExcluded = false;
20
 
21
  /**
@@ -27,9 +29,12 @@ class AntiCrawler extends \Cleantalk\Common\Firewall\FirewallModule{
27
  */
28
  public function __construct( $log_table, $ac_logs_table, $params = array() ) {
29
 
 
 
30
  $this->db__table__logs = $log_table ?: null;
31
  $this->db__table__ac_logs = $ac_logs_table ?: null;
32
  $this->ua = md5( Server::get('HTTP_USER_AGENT') );
 
33
 
34
  foreach( $params as $param_name => $param ){
35
  $this->$param_name = isset( $this->$param_name ) ? $param : false;
@@ -47,13 +52,18 @@ class AntiCrawler extends \Cleantalk\Common\Firewall\FirewallModule{
47
  public function check() {
48
 
49
  $results = array();
50
-
51
- // Skip by cookie
52
  foreach( $this->ip_array as $ip_origin => $current_ip ) {
53
-
54
- if( Cookie::get('apbct_antibot') == md5( $this->api_key . $current_ip ) ) {
55
-
56
- if( Cookie::get( 'apbct_anticrawler_passed' ) === '1' ){
 
 
 
 
 
 
57
  if( ! headers_sent() )
58
  \Cleantalk\Common\Helper::apbct_cookie__set( 'apbct_anticrawler_passed', '0', time() - 86400, '/', null, false, true, 'Lax' );
59
  }
@@ -64,21 +74,20 @@ class AntiCrawler extends \Cleantalk\Common\Firewall\FirewallModule{
64
 
65
  }
66
  }
67
-
68
  // Common check
69
  foreach( $this->ip_array as $ip_origin => $current_ip ){
70
-
71
  $result = $this->db->fetch(
72
  "SELECT ip"
73
  . ' FROM `' . $this->db__table__ac_logs . '`'
74
  . " WHERE ip = '$current_ip'"
75
- . " AND ua = '$this->ua'"
76
- . " LIMIT 1;"
77
  );
78
 
79
- if( ! empty( $result ) && isset( $result['ip'] ) ){
80
 
81
- if( Cookie::get('apbct_antibot') !== md5( $this->api_key . $current_ip ) ){
82
 
83
  $results[] = array( 'ip' => $current_ip, 'is_personal' => false, 'status' => 'DENY_ANTICRAWLER', );
84
 
@@ -102,8 +111,6 @@ class AntiCrawler extends \Cleantalk\Common\Firewall\FirewallModule{
102
  }
103
 
104
  add_action( 'wp_head', array( '\Cleantalk\ApbctWP\Firewall\AntiCrawler', 'set_cookie' ) );
105
- global $apbct_anticrawler_ip;
106
- $apbct_anticrawler_ip = $current_ip;
107
 
108
  }
109
  }
@@ -139,8 +146,8 @@ class AntiCrawler extends \Cleantalk\Common\Firewall\FirewallModule{
139
 
140
 
141
  public static function set_cookie(){
142
- global $apbct, $apbct_anticrawler_ip;
143
- echo '<script>document.cookie = "apbct_antibot=' . md5( $apbct->api_key . $apbct_anticrawler_ip ) . '; path=/; expires=0; samesite=lax";</script>';
144
  }
145
 
146
  /**
@@ -175,6 +182,8 @@ class AntiCrawler extends \Cleantalk\Common\Firewall\FirewallModule{
175
 
176
  public function _die( $result ){
177
 
 
 
178
  // File exists?
179
  if(file_exists(CLEANTALK_PLUGIN_DIR . "lib/Cleantalk/ApbctWP/Firewall/die_page_anticrawler.html")){
180
 
@@ -189,7 +198,7 @@ class AntiCrawler extends \Cleantalk\Common\Firewall\FirewallModule{
189
  '{REMOTE_ADDRESS}' => $result['ip'],
190
  '{SERVICE_ID}' => $this->apbct->data['service_id'],
191
  '{HOST}' => Server::get( 'HTTP_HOST' ),
192
- '{COOKIE_ANTICRAWLER}' => md5( $this->api_key . $result['ip'] ),
193
  '{COOKIE_ANTICRAWLER_PASSED}' => '1',
194
  '{GENERATED}' => '<p>The page was generated at&nbsp;' . date( 'D, d M Y H:i:s' ) . "</p>",
195
  );
@@ -198,6 +207,20 @@ class AntiCrawler extends \Cleantalk\Common\Firewall\FirewallModule{
198
  $sfw_die_page = str_replace( $place_holder, $replace, $sfw_die_page );
199
  }
200
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
  wp_die($sfw_die_page, "Blacklisted", Array('response'=>403));
202
 
203
  }else{
10
 
11
  public $module_name = 'ANTICRAWLER';
12
 
13
+ private $db__table__ac_logs = null;
14
  private $api_key = '';
15
  private $apbct = false;
16
  private $store_interval = 60;
17
  private $ua; //User-Agent
18
+
19
+ private $ac_log_result = '';
20
+
21
  public $isExcluded = false;
22
 
23
  /**
29
  */
30
  public function __construct( $log_table, $ac_logs_table, $params = array() ) {
31
 
32
+ global $apbct;
33
+ $this->apbct = $apbct;
34
  $this->db__table__logs = $log_table ?: null;
35
  $this->db__table__ac_logs = $ac_logs_table ?: null;
36
  $this->ua = md5( Server::get('HTTP_USER_AGENT') );
37
+
38
 
39
  foreach( $params as $param_name => $param ){
40
  $this->$param_name = isset( $this->$param_name ) ? $param : false;
52
  public function check() {
53
 
54
  $results = array();
55
+
 
56
  foreach( $this->ip_array as $ip_origin => $current_ip ) {
57
+
58
+ // Skip by 301 response code
59
+ if( http_response_code() == 301 ){
60
+ $results[] = array( 'ip' => $current_ip, 'is_personal' => false, 'status' => 'PASS_ANTICRAWLER', );
61
+ return $results;
62
+ }
63
+
64
+ // Skip by cookie
65
+ if( Cookie::get('apbct_antibot') == hash( 'sha256', $this->api_key . $this->apbct->data['salt'] ) ) {
66
+ if( Cookie::get( 'apbct_anticrawler_passed' ) == 1 ){
67
  if( ! headers_sent() )
68
  \Cleantalk\Common\Helper::apbct_cookie__set( 'apbct_anticrawler_passed', '0', time() - 86400, '/', null, false, true, 'Lax' );
69
  }
74
 
75
  }
76
  }
77
+
78
  // Common check
79
  foreach( $this->ip_array as $ip_origin => $current_ip ){
80
+
81
  $result = $this->db->fetch(
82
  "SELECT ip"
83
  . ' FROM `' . $this->db__table__ac_logs . '`'
84
  . " WHERE ip = '$current_ip'"
85
+ . " AND ua = '$this->ua';"
 
86
  );
87
 
88
+ if( isset( $result['ip'] ) ){
89
 
90
+ if( Cookie::get('apbct_antibot') !== hash( 'sha256', $this->api_key . $this->apbct->data['salt'] ) ){
91
 
92
  $results[] = array( 'ip' => $current_ip, 'is_personal' => false, 'status' => 'DENY_ANTICRAWLER', );
93
 
111
  }
112
 
113
  add_action( 'wp_head', array( '\Cleantalk\ApbctWP\Firewall\AntiCrawler', 'set_cookie' ) );
 
 
114
 
115
  }
116
  }
146
 
147
 
148
  public static function set_cookie(){
149
+ global $apbct;
150
+ echo '<script>document.cookie = "apbct_antibot=' . hash( 'sha256', $apbct->api_key . $apbct->data['salt'] ) . '; path=/; expires=0; samesite=lax";</script>';
151
  }
152
 
153
  /**
182
 
183
  public function _die( $result ){
184
 
185
+ global $apbct;
186
+
187
  // File exists?
188
  if(file_exists(CLEANTALK_PLUGIN_DIR . "lib/Cleantalk/ApbctWP/Firewall/die_page_anticrawler.html")){
189
 
198
  '{REMOTE_ADDRESS}' => $result['ip'],
199
  '{SERVICE_ID}' => $this->apbct->data['service_id'],
200
  '{HOST}' => Server::get( 'HTTP_HOST' ),
201
+ '{COOKIE_ANTICRAWLER}' => hash( 'sha256', $apbct->api_key . $apbct->data['salt'] ),
202
  '{COOKIE_ANTICRAWLER_PASSED}' => '1',
203
  '{GENERATED}' => '<p>The page was generated at&nbsp;' . date( 'D, d M Y H:i:s' ) . "</p>",
204
  );
207
  $sfw_die_page = str_replace( $place_holder, $replace, $sfw_die_page );
208
  }
209
 
210
+ if( isset( $_GET['debug'] ) ){
211
+ $debug = '<h1>Headers</h1>'
212
+ . str_replace( "\n", "<br>", print_r( \apache_request_headers(), true ) )
213
+ . '<h1>$_SERVER</h1>'
214
+ . str_replace( "\n", "<br>", print_r( $_SERVER, true ) )
215
+ . '<h1>AC_LOG_RESULT</h1>'
216
+ . str_replace( "\n", "<br>", print_r( $this->ac_log_result, true ) )
217
+ . '<h1>IPS</h1>'
218
+ . str_replace( "\n", "<br>", print_r( $this->ip_array, true ) );
219
+ }else{
220
+ $debug = '';
221
+ }
222
+ $sfw_die_page = str_replace( "{DEBUG}", $debug, $sfw_die_page );
223
+
224
  wp_die($sfw_die_page, "Blacklisted", Array('response'=>403));
225
 
226
  }else{
lib/Cleantalk/ApbctWP/Firewall/SFW.php CHANGED
@@ -206,6 +206,8 @@ class SFW extends \Cleantalk\Common\Firewall\FirewallModule {
206
  */
207
  public function _die( $result ){
208
 
 
 
209
  parent::_die( $result );
210
 
211
  // Statistics
@@ -241,7 +243,7 @@ class SFW extends \Cleantalk\Common\Firewall\FirewallModule {
241
  '{COOKIE_PREFIX}' => '',
242
  '{COOKIE_DOMAIN}' => $this->cookie_domain,
243
  '{COOKIE_SFW}' => $this->test ? $this->test_ip : $cookie_val,
244
- '{COOKIE_ANTICRAWLER}' => md5( $this->api_key . $result['ip'] ),
245
 
246
  // Test
247
  '{TEST_TITLE}' => '',
206
  */
207
  public function _die( $result ){
208
 
209
+ global $apbct;
210
+
211
  parent::_die( $result );
212
 
213
  // Statistics
243
  '{COOKIE_PREFIX}' => '',
244
  '{COOKIE_DOMAIN}' => $this->cookie_domain,
245
  '{COOKIE_SFW}' => $this->test ? $this->test_ip : $cookie_val,
246
+ '{COOKIE_ANTICRAWLER}' => hash( 'sha256', $apbct->api_key . $apbct->data['salt'] ),
247
 
248
  // Test
249
  '{TEST_TITLE}' => '',
lib/Cleantalk/ApbctWP/Firewall/die_page_anticrawler.html CHANGED
@@ -153,5 +153,8 @@
153
  countdown();
154
 
155
  </script>
 
 
 
156
  </body>
157
  </html>
153
  countdown();
154
 
155
  </script>
156
+ <div class="debug">
157
+ {DEBUG}
158
+ </div>
159
  </body>
160
  </html>
lib/Cleantalk/Templates/Singleton.php CHANGED
@@ -1,35 +1,35 @@
1
- <?php
2
-
3
- namespace Cleantalk\Templates;
4
-
5
- if(!trait_exists('Cleantalk\Templates\Singleton')) {
6
-
7
- trait Singleton{
8
-
9
- static $instance;
10
-
11
- public function __construct(){}
12
- public function __wakeup(){}
13
- public function __clone(){}
14
-
15
- /**
16
- * Constructor
17
- * @return $this
18
- */
19
- public static function getInstance(){
20
- if (!isset(static::$instance)) {
21
- static::$instance = new static;
22
- static::$instance->init();
23
- }
24
- return static::$instance;
25
- }
26
-
27
- /**
28
- * Alternative constructor
29
- */
30
- private function init(){
31
-
32
- }
33
-
34
- }
35
- }
1
+ <?php
2
+
3
+ namespace Cleantalk\Templates;
4
+
5
+ if(!trait_exists('Cleantalk\Templates\Singleton')) {
6
+
7
+ trait Singleton{
8
+
9
+ static $instance;
10
+
11
+ public function __construct(){}
12
+ public function __wakeup(){}
13
+ public function __clone(){}
14
+
15
+ /**
16
+ * Constructor
17
+ * @return $this
18
+ */
19
+ public static function getInstance(){
20
+ if (!isset(static::$instance)) {
21
+ static::$instance = new static;
22
+ static::$instance->init();
23
+ }
24
+ return static::$instance;
25
+ }
26
+
27
+ /**
28
+ * Alternative constructor
29
+ */
30
+ private function init(){
31
+
32
+ }
33
+
34
+ }
35
+ }
lib/cleantalk-php-patch.php CHANGED
@@ -1,80 +1,91 @@
1
- <?php
2
-
3
- /*
4
- * Patch for apache_request_headers()
5
- * If Apache web server is missing then making
6
- */
7
- if( !function_exists('apache_request_headers') ){
8
- function apache_request_headers(){
9
-
10
- $headers = array();
11
- foreach($_SERVER as $key => $val){
12
- if(preg_match('/\AHTTP_/', $key)){
13
- $server_key = preg_replace('/\AHTTP_/', '', $key);
14
- $key_parts = explode('_', $server_key);
15
- if(count($key_parts) > 0 and strlen($server_key) > 2){
16
- foreach($key_parts as $part_index => $part){
17
- $key_parts[$part_index] = function_exists('mb_strtolower') ? mb_strtolower($part) : strtolower($part);
18
- $key_parts[$part_index][0] = strtoupper($key_parts[$part_index][0]);
19
- }
20
- $server_key = implode('-', $key_parts);
21
- }
22
- $headers[$server_key] = $val;
23
- }
24
- }
25
- return $headers;
26
- }
27
- }
28
-
29
- /*
30
- * Patch for locale_get_display_region()
31
- * For old PHP versions
32
- */
33
- if( !function_exists('locale_get_display_region') ){
34
- function locale_get_display_region($locale, $in_locale = 'EN'){
35
-
36
- return 'Unkonwn' . ($locale ? ': ' . $locale : '');
37
- }
38
- }
39
-
40
- /*
41
- * Patch for utf8_decode()
42
- * If PHP complied without XML support
43
- * From getID3() by James Heinrich <info@getid3.org> under GNU GPL
44
- */
45
- if(!function_exists('utf8_decode')){
46
- function utf8_decode($string){
47
-
48
- $newcharstring = '';
49
- $offset = 0;
50
- $stringlength = strlen($string);
51
- while ($offset < $stringlength) {
52
- if ((ord($string[$offset]) | 0x07) == 0xF7) {
53
- $charval = ((ord($string[($offset + 0)]) & 0x07) << 18) &
54
- ((ord($string[($offset + 1)]) & 0x3F) << 12) &
55
- ((ord($string[($offset + 2)]) & 0x3F) << 6) &
56
- (ord($string[($offset + 3)]) & 0x3F);
57
- $offset += 4;
58
- } elseif ((ord($string[$offset]) | 0x0F) == 0xEF) {
59
- $charval = ((ord($string[($offset + 0)]) & 0x0F) << 12) &
60
- ((ord($string[($offset + 1)]) & 0x3F) << 6) &
61
- (ord($string[($offset + 2)]) & 0x3F);
62
- $offset += 3;
63
- } elseif ((ord($string[$offset]) | 0x1F) == 0xDF) {
64
- $charval = ((ord($string[($offset + 0)]) & 0x1F) << 6) &
65
- (ord($string[($offset + 1)]) & 0x3F);
66
- $offset += 2;
67
- } elseif ((ord($string[$offset]) | 0x7F) == 0x7F) {
68
- $charval = ord($string[$offset]);
69
- $offset += 1;
70
- } else {
71
- $charval = false;
72
- $offset += 1;
73
- }
74
- if ($charval !== false) {
75
- $newcharstring .= (($charval < 256) ? chr($charval) : '?');
76
- }
77
- }
78
- return $newcharstring;
79
- }
 
 
 
 
 
 
 
 
 
 
 
80
  }
1
+ <?php
2
+
3
+ /*
4
+ * Patch for apache_request_headers()
5
+ * If Apache web server is missing then making
6
+ */
7
+ if( !function_exists('apache_request_headers') ){
8
+ function apache_request_headers(){
9
+
10
+ $headers = array();
11
+ foreach($_SERVER as $key => $val){
12
+ if(preg_match('/\AHTTP_/', $key)){
13
+ $server_key = preg_replace('/\AHTTP_/', '', $key);
14
+ $key_parts = explode('_', $server_key);
15
+ if(count($key_parts) > 0 and strlen($server_key) > 2){
16
+ foreach($key_parts as $part_index => $part){
17
+ $key_parts[$part_index] = function_exists('mb_strtolower') ? mb_strtolower($part) : strtolower($part);
18
+ $key_parts[$part_index][0] = strtoupper($key_parts[$part_index][0]);
19
+ }
20
+ $server_key = implode('-', $key_parts);
21
+ }
22
+ $headers[$server_key] = $val;
23
+ }
24
+ }
25
+ return $headers;
26
+ }
27
+ }
28
+
29
+ /*
30
+ * Patch for locale_get_display_region()
31
+ * For old PHP versions
32
+ */
33
+ if( !function_exists('locale_get_display_region') ){
34
+ function locale_get_display_region($locale, $in_locale = 'EN'){
35
+
36
+ return 'Unkonwn' . ($locale ? ': ' . $locale : '');
37
+ }
38
+ }
39
+
40
+ /*
41
+ * Patch for utf8_decode()
42
+ * If PHP complied without XML support
43
+ * From getID3() by James Heinrich <info@getid3.org> under GNU GPL
44
+ */
45
+ if(!function_exists('utf8_decode')){
46
+ function utf8_decode($string){
47
+
48
+ $newcharstring = '';
49
+ $offset = 0;
50
+ $stringlength = strlen($string);
51
+ while ($offset < $stringlength) {
52
+ if ((ord($string[$offset]) | 0x07) == 0xF7) {
53
+ $charval = ((ord($string[($offset + 0)]) & 0x07) << 18) &
54
+ ((ord($string[($offset + 1)]) & 0x3F) << 12) &
55
+ ((ord($string[($offset + 2)]) & 0x3F) << 6) &
56
+ (ord($string[($offset + 3)]) & 0x3F);
57
+ $offset += 4;
58
+ } elseif ((ord($string[$offset]) | 0x0F) == 0xEF) {
59
+ $charval = ((ord($string[($offset + 0)]) & 0x0F) << 12) &
60
+ ((ord($string[($offset + 1)]) & 0x3F) << 6) &
61
+ (ord($string[($offset + 2)]) & 0x3F);
62
+ $offset += 3;
63
+ } elseif ((ord($string[$offset]) | 0x1F) == 0xDF) {
64
+ $charval = ((ord($string[($offset + 0)]) & 0x1F) << 6) &
65
+ (ord($string[($offset + 1)]) & 0x3F);
66
+ $offset += 2;
67
+ } elseif ((ord($string[$offset]) | 0x7F) == 0x7F) {
68
+ $charval = ord($string[$offset]);
69
+ $offset += 1;
70
+ } else {
71
+ $charval = false;
72
+ $offset += 1;
73
+ }
74
+ if ($charval !== false) {
75
+ $newcharstring .= (($charval < 256) ? chr($charval) : '?');
76
+ }
77
+ }
78
+ return $newcharstring;
79
+ }
80
+ }
81
+
82
+ if( ! function_exists( "array_column" ) ){
83
+
84
+ function array_column($array,$column_name){
85
+
86
+ return array_map( function ( $element ) use ( $column_name ){
87
+ return $element[ $column_name ];
88
+ }, $array );
89
+
90
+ }
91
  }
readme.txt CHANGED
@@ -1,10 +1,10 @@
1
  === Spam protection, AntiSpam, FireWall by CleanTalk ===
2
  Contributors: safronik
3
- Tags: spam, antispam, woocommerce, comments, firewall
4
  Requires at least: 3.0
5
  Tested up to: 5.5
6
  Requires PHP: 5.4
7
- Stable tag: 5.146
8
  License: GPLv2
9
 
10
  Spam protection, anti-spam, firewall, premium plugin. No spam comments & users, no spam contact form & WooCommerce anti-spam.
@@ -194,7 +194,6 @@ our own CleanTalk Cloud Service. Anti Spam by CleanTalk offers a free trial, you
194
 
195
  = Additional features =
196
  * Daily and weekly detailed anti-spam reports: traffic VS spam.
197
- * Apps for iPhone, Android to control anti-spam service, comments, signups, contacts, traffic and spam stats for the last 7 days.
198
  * AntiSpam apps for most popular CMS on cleantalk.org.
199
 
200
  = How to protect sites from spam bots without CAPTCHA? =
@@ -317,11 +316,6 @@ In WordPress multisite version you can switch the plugin to use Global Access ke
317
  **Make it before you activated the plugin. If the plugin already activated, deactivate it and add the code and active it again.**
318
  Now, all subsites will have this access key.
319
 
320
- = Manage and control spam protection =
321
-
322
- Go to <a href="https://cleantalk.org/my" target="_blank">Dashboard</a> at the cleantalk.org or use <a href="https://play.google.com/store/apps/details?id=org.cleantalk.app">Android</a>, <a href="https://itunes.apple.com/us/app/cleantalk/id825479913?mt=8">iPhone</a> anti-spam app to manage and control spam protection.
323
-
324
-
325
  == Frequently Asked Questions ==
326
 
327
  = Why are they spamming me? =
@@ -580,6 +574,14 @@ If your website has forms that send data to external sources, you can enable opt
580
 
581
  == Changelog ==
582
 
 
 
 
 
 
 
 
 
583
  = 5.146 Sep 17 2020 =
584
  * Fix: Deprecated function wp_blacklist_check() fixed.
585
  * Fix: Roles exclusion fixed.
1
  === Spam protection, AntiSpam, FireWall by CleanTalk ===
2
  Contributors: safronik
3
+ Tags: spam, antispam, anti-spam, comments, firewall
4
  Requires at least: 3.0
5
  Tested up to: 5.5
6
  Requires PHP: 5.4
7
+ Stable tag: 5.146.1
8
  License: GPLv2
9
 
10
  Spam protection, anti-spam, firewall, premium plugin. No spam comments & users, no spam contact form & WooCommerce anti-spam.
194
 
195
  = Additional features =
196
  * Daily and weekly detailed anti-spam reports: traffic VS spam.
 
197
  * AntiSpam apps for most popular CMS on cleantalk.org.
198
 
199
  = How to protect sites from spam bots without CAPTCHA? =
316
  **Make it before you activated the plugin. If the plugin already activated, deactivate it and add the code and active it again.**
317
  Now, all subsites will have this access key.
318
 
 
 
 
 
 
319
  == Frequently Asked Questions ==
320
 
321
  = Why are they spamming me? =
574
 
575
  == Changelog ==
576
 
577
+ = 5.146.1 Sep 23 2020 =
578
+ * Fix: URL exclusions setting.
579
+ * Fix: Login scripts output fixed.
580
+ * Fix: Updater function name fixed.
581
+ * New: Debug mode for Anti-Crawler.
582
+ * Fix: Pass AC check if 301 HTTP response code received.
583
+ * Fix: Antibot cookie value fixed.
584
+
585
  = 5.146 Sep 17 2020 =
586
  * Fix: Deprecated function wp_blacklist_check() fixed.
587
  * Fix: Roles exclusion fixed.