Cerber Security & Antispam - Version 6.5

Version Description

  • New: A new, advanced initialization mode which reinforces overall security performance.
  • New: Traffic Inspector's algorithms detect and deny any attempt to upload executable files or an .htaccess file via any POST request.
  • New: A new setting to disable email notifications about new versions of the plugin.
  • New: Search in the traffic log improved. Search in the User agent string and filter out the HTTP method (GET/POST) are available.
  • Update: Performance of the logging subsystem is improved.
  • Update: In the Smart mode if a user is not logged in, all requests to the admin dashboard are logged.
  • Bug fixed: If a user tries to log in with an email address and an incorrect password, the "Invalid username" message is shown.
  • Bug fixed: On a multisite installation with websites in subdirectories a user activation link doesn't work.
  • Read more
Download this release

Release Info

Developer Gioni
Plugin Icon 128x128 Cerber Security & Antispam
Version 6.5
Comparing to
See all releases

Code changes from version 6.2 to 6.5

assets/admin.css CHANGED
@@ -357,6 +357,17 @@ td.crb-traffic-details div{
357
  #crb-traffic-form select{
358
  width: 100%;
359
  }
 
 
 
 
 
 
 
 
 
 
 
360
 
361
  /* IP info like WHOIS details */
362
 
@@ -455,7 +466,7 @@ p.act-url{
455
  border-right: 4px solid rgba(0, 0, 0, 0);
456
  }
457
 
458
- .red_label, .actv10, .actv11, .actv12, .actv16, .actv17, .actv18, .actv19, .actv41, .actv42, .actv53, .actv54, .actv55, .actv70, .actv71 {
459
  display: inline-block;
460
  padding: 3px 5px 3px 5px;
461
  /*margin: 1px;*/
@@ -783,9 +794,9 @@ div#whois:hover {
783
  #diagnostic .diag-section {
784
  background-color: #f7f7f7;
785
  border: 2px solid #ccc;
786
- width: 100%;
787
  max-width:1000px;
788
- margin-top: 1em;
789
  padding: 1em;
790
  }
791
  #diagnostic table {
@@ -817,6 +828,13 @@ div#whois:hover {
817
  width:50%;
818
  }
819
 
 
 
 
 
 
 
 
820
 
821
  .cerber-button span.dashicons-before {
822
  display: inline-block;
@@ -900,11 +918,16 @@ table#admin-help tbody td {
900
  table#admin-help h3,
901
  table#admin-help img{
902
  margin-top: 30px;
 
903
  }
904
  table#admin-help p{
905
  margin-top: 0.5em;
906
  margin-bottom: 1em;
907
  }
 
 
 
 
908
 
909
  /* Help sign */
910
 
357
  #crb-traffic-form select{
358
  width: 100%;
359
  }
360
+ #crb-traffic-form input[type=submit]{
361
+ font-weight: bold;
362
+ margin-top: 10px;
363
+ }
364
+ #crb-traffic-form p {
365
+ padding: 0 !important;
366
+ }
367
+ #crb-traffic-form label {
368
+ font-weight: bold;
369
+ color: #333;
370
+ }
371
 
372
  /* IP info like WHOIS details */
373
 
466
  border-right: 4px solid rgba(0, 0, 0, 0);
467
  }
468
 
469
+ .red_label, .actv10, .actv11, .actv12, .actv16, .actv17, .actv18, .actv19, .actv41, .actv42, .actv53, .actv54, .actv55, .actv56, .actv70, .actv71 {
470
  display: inline-block;
471
  padding: 3px 5px 3px 5px;
472
  /*margin: 1px;*/
794
  #diagnostic .diag-section {
795
  background-color: #f7f7f7;
796
  border: 2px solid #ccc;
797
+ width: 90%;
798
  max-width:1000px;
799
+ margin-bottom: 1em;
800
  padding: 1em;
801
  }
802
  #diagnostic table {
828
  width:50%;
829
  }
830
 
831
+ .crb-plain-table {
832
+ border-collapse: collapse;
833
+ margin-top: 1em;
834
+ }
835
+ .crb-plain-table td{
836
+ border: 1px solid #eee;
837
+ }
838
 
839
  .cerber-button span.dashicons-before {
840
  display: inline-block;
918
  table#admin-help h3,
919
  table#admin-help img{
920
  margin-top: 30px;
921
+ margin-bottom: 1em;
922
  }
923
  table#admin-help p{
924
  margin-top: 0.5em;
925
  margin-bottom: 1em;
926
  }
927
+ table#admin-help span{
928
+ vertical-align: middle;
929
+ display: inline-block;
930
+ }
931
 
932
  /* Help sign */
933
 
assets/admin.js CHANGED
@@ -3,7 +3,7 @@ jQuery(document).ready(function ($) {
3
  /* WP Comments page */
4
  var comtable = 'table.wp-list-table.comments';
5
 
6
- if (crb_lab_available && $(comtable).length) {
7
  $(comtable + " td.column-author").each(function (index) {
8
  var ip = $(this).find('a').last().text();
9
  var ip_id = cerber_get_id_ip(ip);
3
  /* WP Comments page */
4
  var comtable = 'table.wp-list-table.comments';
5
 
6
+ if (typeof crb_lab_available !== 'undefined' && crb_lab_available && $(comtable).length) {
7
  $(comtable + " td.column-author").each(function (index) {
8
  var ip = $(this).find('a').last().text();
9
  var ip_id = cerber_get_id_ip(ip);
assets/bn2ra.png ADDED
Binary file
cerber-lab.php CHANGED
@@ -511,21 +511,27 @@ function lab_is_cloud_ok(){
511
  */
512
  function lab_save_push( $ip, $reason_id, $details ) {
513
  global $wpdb;
514
- if ( !$ip || is_ip_private( $ip ) || cerber_acl_check( $ip, 'W' ) || !(crb_get_settings( 'cerberlab' ) || lab_lab())) {
 
515
  return;
516
  }
 
517
  if ($reason_id == 8){
518
  $details = array( 'uri' => $_SERVER['REQUEST_URI'] );
519
  }
520
  if ( is_array( $details ) ) {
521
  $details = serialize( $details );
522
  }
 
523
  $wpdb->insert( CERBER_LAB_TABLE, array(
524
  'ip' => $ip,
525
  'reason_id' => $reason_id,
526
  'details' => $details,
527
  'stamp' => time(),
528
  ), array( '%s', '%d', '%s', '%d' ) );
 
 
 
529
  }
530
  /**
531
  * Get data for lab
@@ -648,10 +654,9 @@ function lab_lab( $with_date = false ) {
648
  if ( empty( $key[2] ) || empty( $key[3] ) ) {
649
  return false;
650
  }
651
- if ( time() > $key[3] ) {
652
  return false;
653
  }
654
-
655
  if ( ! $with_date ) {
656
  return true;
657
  }
@@ -660,16 +665,17 @@ function lab_lab( $with_date = false ) {
660
  $gmt_offset = cerber_get_site_option( 'gmt_offset' ) * 3600;
661
 
662
  return date_i18n( $df, $gmt_offset + $key[3] );
663
-
664
- //return $key[3];
665
  }
666
 
667
  function lab_indicator(){
668
- if (lab_is_cloud_ok()){
669
  $key = lab_get_key();
670
  $sid = 'Site ID: '.$key[0];
671
- return '<div title="'.$sid.'" style="float: right; font-weight: normal; font-size: 80%; padding: 0.35em 0.6em 0.35em 0.6em; color: #fff; background-color: #51AE43;"><span style="vertical-align: top; line-height: 1;" class="dashicons dashicons-yes"></span> Cerber Security Cloud Protection is active</div>';
 
672
  }
 
 
673
  }
674
 
675
  /**
@@ -882,4 +888,13 @@ function lab_geo_update( $ip = '', $data = array() ) {
882
  }
883
  }
884
  }
 
 
 
 
 
 
 
 
 
885
  }
511
  */
512
  function lab_save_push( $ip, $reason_id, $details ) {
513
  global $wpdb;
514
+ $ip = filter_var( $ip, FILTER_VALIDATE_IP );
515
+ if ( ! $ip || is_ip_private( $ip ) || cerber_acl_check( $ip, 'W' ) || ! ( crb_get_settings( 'cerberlab' ) || lab_lab() ) ) {
516
  return;
517
  }
518
+ $reason_id = absint( $reason_id );
519
  if ($reason_id == 8){
520
  $details = array( 'uri' => $_SERVER['REQUEST_URI'] );
521
  }
522
  if ( is_array( $details ) ) {
523
  $details = serialize( $details );
524
  }
525
+ /*
526
  $wpdb->insert( CERBER_LAB_TABLE, array(
527
  'ip' => $ip,
528
  'reason_id' => $reason_id,
529
  'details' => $details,
530
  'stamp' => time(),
531
  ), array( '%s', '%d', '%s', '%d' ) );
532
+ */
533
+ $details = cerber_real_escape( $details );
534
+ cerber_db_query( 'INSERT INTO ' . CERBER_LAB_TABLE . ' (ip, reason_id, details, stamp) VALUES ("' . $ip . '",' . $reason_id . ',"' . $details . '",' . time() . ')' );
535
  }
536
  /**
537
  * Get data for lab
654
  if ( empty( $key[2] ) || empty( $key[3] ) ) {
655
  return false;
656
  }
657
+ if ( time() > ( $key[3] + 86400 ) ) { // Plus grace period
658
  return false;
659
  }
 
660
  if ( ! $with_date ) {
661
  return true;
662
  }
665
  $gmt_offset = cerber_get_site_option( 'gmt_offset' ) * 3600;
666
 
667
  return date_i18n( $df, $gmt_offset + $key[3] );
 
 
668
  }
669
 
670
  function lab_indicator(){
671
+ if ( lab_is_cloud_ok() && lab_lab() ) {
672
  $key = lab_get_key();
673
  $sid = 'Site ID: '.$key[0];
674
+ return '<div title="'.$sid.'" style="float: right; font-weight: normal; font-size: 80%; padding: 0.35em 0.6em 0.35em 0.6em; color: #fff; background-color: #29AD16;"><span style="vertical-align: top; line-height: 1;" class="dashicons dashicons-shield-alt"></span></div>';
675
+ //return '<div title="'.$sid.'" style="float: right; font-weight: normal; font-size: 80%; padding: 0.35em 0.6em 0.35em 0.6em; color: #fff; background-color: #51AE43;"><span style="vertical-align: top; line-height: 1;" class="dashicons dashicons-yes"></span> Cerber Security Cloud Protection is active</div>';
676
  }
677
+
678
+ return '';
679
  }
680
 
681
  /**
888
  }
889
  }
890
  }
891
+ }
892
+
893
+ function lab_cleanup_cache() {
894
+ global $wpdb;
895
+ if ( ! current_user_can( 'manage_options' ) ) {
896
+ return;
897
+ }
898
+ $wpdb->query( 'TRUNCATE TABLE ' . CERBER_LAB_NET_TABLE );
899
+ $wpdb->query( 'TRUNCATE TABLE ' . CERBER_LAB_IP_TABLE );
900
  }
cerber-load.php ADDED
@@ -0,0 +1,4976 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Copyright (C) 2015-18 CERBER TECH INC., http://cerber.tech
4
+ Copyright (C) 2015-18 Gregory Markov, https://wpcerber.com
5
+
6
+ Licenced under the GNU GPL.
7
+
8
+ This program is free software; you can redistribute it and/or modify
9
+ it under the terms of the GNU General Public License as published by
10
+ the Free Software Foundation; either version 3 of the License, or
11
+ (at your option) any later version.
12
+
13
+ This program is distributed in the hope that it will be useful,
14
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ GNU General Public License for more details.
17
+
18
+ You should have received a copy of the GNU General Public License
19
+ along with this program; if not, write to the Free Software
20
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
+
22
+ */
23
+
24
+ /*
25
+
26
+
27
+
28
+ ▄████▄ ▓█████ ██▀███ ▄▄▄▄ ▓█████ ██▀███
29
+ ▒██▀ ▀█ ▓█ ▀ ▓██ ▒ ██▒ ▓█████▄ ▓█ ▀ ▓██ ▒ ██▒
30
+ ▒▓█ ▄ ▒███ ▓██ ░▄█ ▒ ▒██▒ ▄██ ▒███ ▓██ ░▄█ ▒
31
+ ▒▓▓▄ ▄██▒ ▒▓█ ▄ ▒██▀▀█▄ ▒██░█▀ ▒▓█ ▄ ▒██▀▀█▄
32
+ ▒ ▓███▀ ░ ░▒████▒ ░██▓ ▒██▒ ░▓█ ▀█▓ ░▒████▒ ░██▓ ▒██▒
33
+ ░ ░▒ ▒ ░ ░░ ▒░ ░ ░ ▒▓ ░▒▓░ ░▒▓███▀▒ ░░ ▒░ ░ ░ ▒▓ ░▒▓░
34
+ ░ ▒ ░ ░ ░ ░▒ ░ ▒░ ▒░▒ ░ ░ ░ ░ ░▒ ░ ▒░
35
+ ░ ░ ░░ ░ ░ ░ ░ ░░ ░
36
+ ░ ░ ░ ░ ░ ░ ░ ░ ░
37
+ ░ ░
38
+
39
+
40
+
41
+
42
+ *========================================================================*
43
+ | |
44
+ | ATTENTION! Do not change or edit this file! |
45
+ | |
46
+ *========================================================================*
47
+
48
+ */
49
+
50
+ // If this file is called directly, abort executing.
51
+ if ( ! defined( 'WPINC' ) ) {
52
+ exit;
53
+ }
54
+
55
+ define( 'CERBER_LOG_TABLE', 'cerber_log' );
56
+ define( 'CERBER_TRAF_TABLE', 'cerber_traffic' );
57
+ define( 'CERBER_ACL_TABLE', 'cerber_acl' );
58
+ define( 'CERBER_BLOCKS_TABLE', 'cerber_blocks' );
59
+ define( 'CERBER_LAB_TABLE', 'cerber_lab' );
60
+ define( 'CERBER_LAB_IP_TABLE', 'cerber_lab_ip' );
61
+ define( 'CERBER_LAB_NET_TABLE', 'cerber_lab_net' );
62
+ define( 'CERBER_GEO_TABLE', 'cerber_countries' );
63
+
64
+ define( 'CERBER_MARKER1', 'WP CERBER GROOVE' );
65
+
66
+ define( 'WP_LOGIN_SCRIPT', 'wp-login.php' );
67
+ define( 'WP_REG_URI', 'wp-register.php' );
68
+ define( 'WP_XMLRPC_SCRIPT', 'xmlrpc.php' );
69
+ define( 'WP_TRACKBACK_SCRIPT', 'wp-trackback.php' );
70
+ define( 'WP_PING_SCRIPT', 'wp-trackback.php' );
71
+ define( 'WP_SIGNUP_SCRIPT', 'wp-signup.php' );
72
+
73
+ define( 'GOO_RECAPTCHA_URL', 'https://www.google.com/recaptcha/api/siteverify' );
74
+
75
+ define( 'CERBER_REQ_PHP', '5.3.0' );
76
+ define( 'CERBER_REQ_WP', '4.4' );
77
+ define( 'CERBER_TECH', 'https://cerber.tech/' );
78
+
79
+ require_once( dirname( __FILE__ ) . '/cerber-pluggable.php' );
80
+ require_once( dirname( __FILE__ ) . '/common.php' );
81
+ require_once( dirname( __FILE__ ) . '/settings.php' );
82
+ require_once( dirname( __FILE__ ) . '/cerber-lab.php' );
83
+ require_once( dirname( __FILE__ ) . '/whois.php' );
84
+ require_once( dirname( __FILE__ ) . '/jetflow.php' );
85
+ require_once( dirname( __FILE__ ) . '/cerber-news.php' );
86
+
87
+ if ( defined( 'WP_ADMIN' ) || defined( 'WP_NETWORK_ADMIN' ) ) {
88
+ // Load dashboard stuff
89
+ require_once( dirname( __FILE__ ) . '/dashboard.php' );
90
+ }
91
+
92
+ // =============================================================================================
93
+
94
+ class WP_Cerber {
95
+ private $remote_ip;
96
+ private $session_id;
97
+ private $status = null;
98
+ private $options;
99
+ private $locked = null; // IP has been locked out
100
+
101
+ private $recaptcha = null; // Can recaptcha be verified with current request
102
+ private $recaptcha_verified = null; // Is recaptcha successfully verified with current request
103
+ public $recaptcha_here = null; // Is recaptcha widget enabled on the currently displayed page
104
+
105
+ private $uri_prohibited = null;
106
+ private $deny = null;
107
+ private $acl = null;
108
+
109
+ //private $boot_source_file = '';
110
+ //private $boot_target_file = '';
111
+
112
+ public $garbage = false; // Garbage has been deleted
113
+
114
+ final function __construct() {
115
+
116
+ $this->session_id = substr(str_shuffle('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'), 0, 24);
117
+
118
+ // Load settings with filling missing (not-set) array keys
119
+ $this->options = crb_get_settings(); // @since 6.3.3
120
+ $keys = array();
121
+ //$defaults = array();
122
+ foreach ( cerber_get_defaults() as $item ) {
123
+ $keys = array_merge( $keys, array_keys( $item ) );
124
+ //$defaults = array_merge( $defaults, $item );
125
+ }
126
+ foreach ( $keys as $key ) {
127
+ if ( ! isset( $this->options[ $key ] ) ) {
128
+ $this->options[ $key ] = null;
129
+ }
130
+ }
131
+
132
+ if ( defined( 'CERBER_IP_KEY' ) ) {
133
+ $this->remote_ip = filter_var( $_SERVER[ CERBER_IP_KEY ], FILTER_VALIDATE_IP );
134
+ }
135
+ elseif ( $this->options['proxy'] && isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
136
+ $list = explode( ',', $_SERVER['HTTP_X_FORWARDED_FOR'] );
137
+ foreach ( $list as $maybe_ip ) {
138
+ $this->remote_ip = filter_var( trim( $maybe_ip ), FILTER_VALIDATE_IP );
139
+ if ( $this->remote_ip ) {
140
+ break;
141
+ }
142
+ }
143
+ if ( ! $this->remote_ip && isset( $_SERVER['HTTP_X_REAL_IP'] ) ) {
144
+ $this->remote_ip = filter_var( $_SERVER['HTTP_X_REAL_IP'], FILTER_VALIDATE_IP );
145
+ }
146
+ } else {
147
+ if ( isset( $_SERVER['REMOTE_ADDR'] ) ) {
148
+ $this->remote_ip = $_SERVER['REMOTE_ADDR'];
149
+ } elseif ( isset( $_SERVER['HTTP_X_REAL_IP'] ) ) {
150
+ $this->remote_ip = $_SERVER['HTTP_X_REAL_IP'];
151
+ } elseif ( isset( $_SERVER['HTTP_CLIENT_IP'] ) ) {
152
+ $this->remote_ip = $_SERVER['HTTP_CLIENT_IP'];
153
+ } elseif ( isset( $_SERVER['SERVER_ADDR'] ) ) {
154
+ $this->remote_ip = $_SERVER['SERVER_ADDR'];
155
+ }
156
+ $this->remote_ip = filter_var( $this->remote_ip, FILTER_VALIDATE_IP );
157
+ }
158
+ // No IP address was found? Roll back to localhost.
159
+ if ( ! $this->remote_ip ) {
160
+ $this->remote_ip = '127.0.0.1';
161
+ } // including WP-CLI, other way is: if defined('WP_CLI')
162
+
163
+ $this->remote_ip = cerber_short_ipv6( $this->remote_ip );
164
+
165
+ $this->reCaptchaInit();
166
+
167
+ $this->deleteGarbage();
168
+
169
+ // Condition to check reCAPTCHA
170
+
171
+ add_action( 'login_init', array( $this, 'reCaptchaNow' ) );
172
+
173
+ }
174
+
175
+ /**
176
+ * @since 6.3.3
177
+ */
178
+ final public function isURIProhibited() {
179
+ global $cerber_status;
180
+
181
+ if ( isset( $this->uri_prohibited ) ) {
182
+ return $this->uri_prohibited;
183
+ }
184
+
185
+ if ( cerber_acl_check() == 'W' ) {
186
+ $this->uri_prohibited = false;
187
+ return false;
188
+ }
189
+
190
+ $script = cerber_last_uri();
191
+ if ( substr( $script, - 4 ) != '.php' ) {
192
+ $script .= '.php'; // Apache MultiViews enabled?
193
+ }
194
+
195
+ if ( $script ) {
196
+ if ( $script == WP_LOGIN_SCRIPT || $script == WP_SIGNUP_SCRIPT || ( $script == WP_REG_URI && ! get_option( 'users_can_register' ) ) ) { // no direct access
197
+ if ( !empty( $this->options['wplogin'] ) ) {
198
+ cerber_log( 50 );
199
+ cerber_soft_block_add( $this->remote_ip, 2, $script );
200
+ $this->uri_prohibited = true;
201
+ return true;
202
+ }
203
+ if ( $this->isDeny() || !empty( $this->options['loginnowp'] ) ) {
204
+ cerber_log( 50 );
205
+ $this->uri_prohibited = true;
206
+ return true;
207
+ }
208
+ }
209
+ elseif ( $script == WP_XMLRPC_SCRIPT || $script == WP_TRACKBACK_SCRIPT ) { // no direct access
210
+ if ( $this->isDeny() || ! empty( $this->options['xmlrpc'] ) ) {
211
+ cerber_log( 50 ); // @since 5.21
212
+ $this->uri_prohibited = true;
213
+ return true;
214
+ }
215
+ if ( !cerber_geo_allowed( 'geo_xmlrpc' ) ) {
216
+ $cerber_status = 16;
217
+ cerber_log( 71 );
218
+ $this->uri_prohibited = true;
219
+ return true;
220
+ }
221
+ }
222
+ }
223
+
224
+ $this->uri_prohibited = false;
225
+
226
+ return $this->uri_prohibited;
227
+ }
228
+
229
+ /**
230
+ * @since 6.3.3
231
+ */
232
+ final public function CheckProhibitedURI(){
233
+ if ($this->isURIProhibited()){
234
+ if ( $this->options['page404'] ) {
235
+ cerber_404_page();
236
+ }
237
+
238
+ return true;
239
+ }
240
+
241
+ return false;
242
+ }
243
+
244
+ /**
245
+ * @since 6.3.3
246
+ */
247
+ final public function InspectRequest(){
248
+ $deny = false;
249
+ $act = 18;
250
+ if ( cerber_is_http_post() ) {
251
+ if (cerber_acl_check(null, 'B')) {
252
+ $deny = true;
253
+ $act = 18;
254
+ }
255
+ }
256
+ if ( !$deny && $_FILES ) {
257
+ $file_names = array();
258
+ foreach ( $_FILES as $file ) {
259
+ if ( is_array( $file['name'] ) ) {
260
+ $file_names = array_merge( $file_names, $file['name'] );
261
+ }
262
+ else {
263
+ $file_names[] = $file['name'];
264
+ }
265
+ }
266
+ foreach ( $file_names as $item ) {
267
+ if ( $reason = $this->isProhibitedFilename( $item ) ) {
268
+ $deny = true;
269
+ $act = $reason;
270
+ break;
271
+ }
272
+ }
273
+ }
274
+ if ( $deny ) {
275
+ cerber_log( $act );
276
+ cerber_forbidden_page();
277
+ }
278
+ }
279
+
280
+ /**
281
+ * @since 6.3.3
282
+ */
283
+ final public function isProhibitedFilename( $file_name ) {
284
+ $prohibited = array( '.htaccess' );
285
+ if ( in_array( $file_name, $prohibited ) ) {
286
+ return 57;
287
+ }
288
+ if ( cerber_detect_exec_extension( $file_name, array('js') ) ) {
289
+ return 56;
290
+ }
291
+
292
+ return false;
293
+ }
294
+
295
+ /**
296
+ * @since 6.3.3
297
+ */
298
+ final public function isDeny() {
299
+ if ( ! isset( $this->deny ) ) {
300
+ $this->acl = cerber_acl_check();
301
+ if ( $this->acl == 'B' || ! cerber_is_allowed() ) {
302
+ $this->deny = true;
303
+ }
304
+ else {
305
+ $this->deny = false;
306
+ }
307
+ }
308
+
309
+ return $this->deny;
310
+ }
311
+
312
+ // TODO: replace it with cerber_get_remote_ip()
313
+ final public function getRemoteIp() {
314
+ return $this->remote_ip;
315
+ }
316
+
317
+ final public function getSessionID() {
318
+ return $this->session_id;
319
+ }
320
+
321
+ final public function getStatus() {
322
+ if (isset($this->status)) return $this->status;
323
+
324
+ $this->status = 0; // Default
325
+
326
+ if ( cerber_is_citadel() ) {
327
+ $this->status = 3;
328
+ }
329
+ else {
330
+ //if ( ! cerber_is_allowed( $this->remote_ip ) ) {
331
+ if ( cerber_block_check( $this->remote_ip ) ) {
332
+ $this->status = 2;
333
+ }
334
+ else {
335
+ $tag = cerber_acl_check( $this->remote_ip );
336
+ if ( $tag == 'W' ) {
337
+ //$this->status = 4;
338
+ }
339
+ elseif ( $tag == 'B' || lab_is_blocked($this->remote_ip, false)) {
340
+ $this->status = 1;
341
+ }
342
+ }
343
+ }
344
+
345
+ return $this->status;
346
+ }
347
+
348
+ /*
349
+ Return Error message in context
350
+ */
351
+ final public function getErrorMsg() {
352
+ $status = $this->getStatus();
353
+ switch ( $status ) {
354
+ case 1:
355
+ case 3:
356
+ return apply_filters( 'cerber_msg_blocked', __( 'You are not allowed to log in. Ask your administrator for assistance.', 'wp-cerber' ) , $status);
357
+ case 2:
358
+ $block = cerber_get_block();
359
+ $min = 1 + ( $block->block_until - time() ) / 60;
360
+
361
+ return apply_filters( 'cerber_msg_reached',
362
+ sprintf( __( 'You have reached the login attempts limit. Please try again in %d minutes.', 'wp-cerber' ), $min ),
363
+ $min );
364
+ break;
365
+ default:
366
+ return '';
367
+ }
368
+ }
369
+
370
+ /*
371
+ Return Remain message in context
372
+ */
373
+ final public function getRemainMsg() {
374
+ $acl = !$this->options['limitwhite'];
375
+ $remain = cerber_get_remain_count($this->remote_ip, $acl);
376
+ if ( $remain < $this->options['attempts'] ) {
377
+ if ( $remain == 0 ) {
378
+ $remain = 1; // with some settings or when lockout was manually removed, we need to have 1 attempt.
379
+ }
380
+ return apply_filters( 'cerber_msg_remain',
381
+ sprintf( _n( 'You have only one attempt remaining.', 'You have %d attempts remaining.', $remain, 'wp-cerber' ), $remain ),
382
+ $remain );
383
+ }
384
+
385
+ return false;
386
+ }
387
+
388
+ final public function getSettings( $name = null ) {
389
+ if ( ! empty( $name ) ) {
390
+ if ( isset( $this->options[ $name ] ) ) {
391
+ return $this->options[ $name ];
392
+ } else {
393
+ return false;
394
+ }
395
+ }
396
+
397
+ return $this->options;
398
+ }
399
+
400
+ /*
401
+ final public function isProhibited( $username ) {
402
+ if ( empty( $this->options['prohibited'] ) ) {
403
+ return false;
404
+ }
405
+
406
+ return in_array( $username, (array) $this->options['prohibited'] );
407
+ }*/
408
+
409
+ /**
410
+ * Adding reCAPTCHA widgets
411
+ *
412
+ */
413
+ final public function reCaptchaInit(){
414
+
415
+ if ( $this->status == 4 || empty( $this->options['sitekey'] ) || empty( $this->options['secretkey'] )) return;
416
+
417
+ // Native WP forms
418
+ add_action( 'login_form', function () {
419
+ global $wp_cerber;
420
+ $wp_cerber->reCaptcha( 'widget', 'recaplogin' );
421
+ } );
422
+ add_filter( 'login_form_middle', function ( $value ) {
423
+ global $wp_cerber;
424
+ $value .= $wp_cerber->reCaptcha( 'widget', 'recaplogin', false );
425
+ return $value;
426
+ });
427
+ add_action( 'lostpassword_form', function () {
428
+ global $wp_cerber;
429
+ $wp_cerber->reCaptcha( 'widget', 'recaplost' );
430
+ } );
431
+ add_action( 'register_form', function () {
432
+ global $wp_cerber;
433
+ if ( !did_action( 'woocommerce_register_form_start' ) ) {
434
+ $wp_cerber->reCaptcha( 'widget', 'recapreg' );
435
+ }
436
+ } );
437
+
438
+ // Support for WooCommerce forms: @since 3.8
439
+ add_action( 'woocommerce_login_form', function () {
440
+ global $wp_cerber;
441
+ $wp_cerber->reCaptcha( 'widget', 'recapwoologin' );
442
+ } );
443
+ add_action( 'woocommerce_lostpassword_form', function () {
444
+ global $wp_cerber;
445
+ $wp_cerber->reCaptcha( 'widget', 'recapwoolost' );
446
+ } );
447
+ add_action( 'woocommerce_register_form', function () {
448
+ global $wp_cerber;
449
+ if ( ! did_action( 'woocommerce_register_form_start' ) ) {
450
+ return;
451
+ }
452
+ $wp_cerber->reCaptcha( 'widget', 'recapwooreg' );
453
+ } );
454
+ add_filter( 'woocommerce_process_login_errors', function ( $validation_error ) {
455
+ global $wp_cerber;
456
+ //$wp_cerber->reCaptchaNow();
457
+ if ( ! $wp_cerber->reCaptchaValidate('woologin', true) ) {
458
+
459
+ return new WP_Error( 'incorrect_recaptcha', $wp_cerber->reCaptchaMsg('woocommerce-login'));
460
+ }
461
+ return $validation_error;
462
+ });
463
+ add_filter( 'allow_password_reset', function ( $var ) { // Note: 'allow_password_reset' also is fired in WP itself
464
+ global $wp_cerber;
465
+ if ( isset( $_POST['wc_reset_password'] ) && did_action( 'woocommerce_init' )) {
466
+ //$wp_cerber->reCaptchaNow();
467
+ if ( ! $wp_cerber->reCaptchaValidate( 'woolost' , true) ) {
468
+
469
+ return new WP_Error( 'incorrect_recaptcha', $wp_cerber->reCaptchaMsg('woocommerce-lost'));
470
+ }
471
+ }
472
+ return $var;
473
+ });
474
+ add_filter( 'woocommerce_process_registration_errors', function ( $validation_error ) {
475
+ global $wp_cerber;
476
+ //$wp_cerber->reCaptchaNow();
477
+ if ( ! $wp_cerber->reCaptchaValidate('wooreg' , true) ) {
478
+
479
+ return new WP_Error( 'incorrect_recaptcha', $wp_cerber->reCaptchaMsg('woocommerce-register'));
480
+ }
481
+ return $validation_error;
482
+ });
483
+
484
+ }
485
+
486
+ /**
487
+ * Generates reCAPTCHA HTML
488
+ *
489
+ * @param string $part 'style' or 'widget'
490
+ * @param null $option what plugin setting must be set to show the reCAPTCHA
491
+ * @param bool $echo if false, return the code, otherwise show it
492
+ *
493
+ * @return null|string
494
+ */
495
+ final public function reCaptcha( $part = '', $option = null, $echo = true ) {
496
+ if ( $this->status == 4 || empty( $this->options['sitekey'] ) || empty( $this->options['secretkey'] )
497
+ || ( $option && empty( $this->options[ $option ] ) )
498
+ ) {
499
+ return null;
500
+ }
501
+
502
+ $sitekey = $this->options['sitekey'];
503
+ $ret = '';
504
+
505
+ switch ( $part ) {
506
+ case 'style': // for default login WP form only - fit it in width nicely.
507
+ ?>
508
+ <style type="text/css" media="all">
509
+ #rc-imageselect, .g-recaptcha {
510
+ transform: scale(0.9);
511
+ -webkit-transform: scale(0.9);
512
+ transform-origin: 0 0;
513
+ -webkit-transform-origin: 0 0;
514
+ }
515
+
516
+ .g-recaptcha {
517
+ margin: 16px 0 20px 0;
518
+ }
519
+ </style>
520
+ <?php
521
+ break;
522
+ case 'widget':
523
+ if ( ! empty( $this->options[ $option ] ) ) {
524
+ $this->recaptcha_here = true;
525
+
526
+ //if ($this->options['invirecap']) $ret = '<div data-size="invisible" class="g-recaptcha" data-sitekey="' . $sitekey . '" data-callback="now_submit_the_form" id="cerber-recaptcha" data-badge="bottomright"></div>';
527
+ if ($this->options['invirecap']) {
528
+ $ret = '<span class="cerber-form-marker"></span><div data-size="invisible" class="g-recaptcha" data-sitekey="' . $sitekey . '" data-callback="now_submit_the_form" id="cerber-recaptcha" data-badge="bottomright"></div>';
529
+ }
530
+ else $ret = '<span class="cerber-form-marker"></span><div class="g-recaptcha" data-sitekey="' . $sitekey . '" data-callback="form_button_enabler" id="cerber-recaptcha"></div>';
531
+
532
+ //$ret = '<span class="cerber-form-marker g-recaptcha"></span>';
533
+
534
+ }
535
+ break;
536
+ }
537
+ if ( $echo ) {
538
+ echo $ret;
539
+ $ret = null;
540
+ }
541
+
542
+ return $ret;
543
+ /*
544
+ <script type="text/javascript">
545
+ var onloadCallback = function() {
546
+ //document.getElementById("wp-submit").disabled = true;
547
+ grecaptcha.render("c-recaptcha", {"sitekey" : "<?php echo $sitekey; ?>" });
548
+ //document.getElementById("wp-submit").disabled = false;
549
+ };
550
+ </script>
551
+ <script src = "https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit&hl=<?php echo $lang; ?>" async defer></script>
552
+ */
553
+ }
554
+
555
+ /**
556
+ * Validate reCAPTCHA by calling Google service
557
+ *
558
+ * @param string $form Form ID (slug)
559
+ * @param boolean $force Force validate without pre-checks
560
+ *
561
+ * @return bool true on success false on failure
562
+ */
563
+ final public function reCaptchaValidate($form = null, $force = false) {
564
+ if (!$force) {
565
+ if ( ! $this->recaptcha || $this->status == 4 ) {
566
+ return true;
567
+ }
568
+ }
569
+
570
+ if ($this->recaptcha_verified != null) return $this->recaptcha_verified;
571
+
572
+ if ( $form == 'comment' && $this->options['recapcomauth'] && is_user_logged_in()) return true;
573
+
574
+ if ( ! $form ) {
575
+ $form = isset( $_REQUEST['action'] ) ? $_REQUEST['action'] : 'login';
576
+ }
577
+
578
+ $forms = array( // known pairs: form => specific plugin setting
579
+ 'lostpassword' => 'recaplost',
580
+ 'register' => 'recapreg',
581
+ 'login' => 'recaplogin',
582
+ 'comment' => 'recapcom',
583
+ 'woologin' => 'recapwoologin',
584
+ 'woolost' => 'recapwoolost',
585
+ 'wooreg' => 'recapwooreg',
586
+ );
587
+
588
+ if ( isset( $forms[ $form ] ) ) {
589
+ if ( empty( $this->options[ $forms[ $form ] ] ) ) {
590
+ return true; // no validation is required
591
+ }
592
+ }
593
+ else {
594
+ return true; // we don't know this form
595
+ }
596
+
597
+ if ( empty( $_POST['g-recaptcha-response'] ) ) {
598
+ $this->reCaptchaFailed($form);
599
+ return false;
600
+ }
601
+
602
+ $result = $this->reCaptchaRequest($_POST['g-recaptcha-response']);
603
+ if ( ! $result ) {
604
+ cerber_log( 42 );
605
+ return false;
606
+ }
607
+
608
+ $result = json_decode( $result );
609
+ $result = obj_to_arr_deep( $result );
610
+
611
+ if ( ! empty( $result['success'] ) ) {
612
+ $this->recaptcha_verified = true;
613
+ return true;
614
+ }
615
+ $this->recaptcha_verified = false;
616
+
617
+ if ( ! empty( $result['error-codes'] ) ) {
618
+ if ( in_array( 'invalid-input-secret', (array) $result['error-codes'] ) ) {
619
+ cerber_log( 41 );
620
+ }
621
+ }
622
+
623
+ $this->reCaptchaFailed($form);
624
+
625
+ return false;
626
+ }
627
+
628
+ final function reCaptchaFailed($context = '') {
629
+ cerber_log( 40 );
630
+ if ($this->options['recaptcha-period'] && $this->options['recaptcha-number'] && $this->options['recaptcha-within']) {
631
+ $remain = cerber_get_remain_count($this->remote_ip , true, 40, $this->options['recaptcha-number'], $this->options['recaptcha-within']);
632
+ if ($remain < 1) cerber_block_add( $this->remote_ip, 5 );
633
+ }
634
+ }
635
+
636
+ /**
637
+ * A form with possible reCAPTCHA has been submitted.
638
+ * Allow to process reCAPTCHA by setting a global flag.
639
+ * Must be called before reCaptchaValidate();
640
+ *
641
+ */
642
+ final public function reCaptchaNow() {
643
+ if ( cerber_is_http_post() && $this->options['sitekey'] && $this->options['secretkey'] ) {
644
+ $this->recaptcha = true;
645
+ }
646
+ }
647
+
648
+ /**
649
+ * Make a request to the Google reCaptcha web service
650
+ *
651
+ * @param string $response Google specific field from the submitted form (widget)
652
+ *
653
+ * @return bool|string Response of the Google service or false on failure
654
+ */
655
+ final public function reCaptchaRequest($response = ''){
656
+
657
+ if (!$response) {
658
+ if (!empty($_POST['g-recaptcha-response'])) $response = $_POST['g-recaptcha-response'];
659
+ else return false;
660
+ }
661
+
662
+ $curl = @curl_init(); // @since 4.32
663
+ if (!$curl) {
664
+ cerber_admin_notice(__( 'ERROR:', 'wp-cerber' ) .' Unable to initialize cURL');
665
+ return false;
666
+ }
667
+
668
+ $opt = curl_setopt_array($curl, array(
669
+ CURLOPT_URL => GOO_RECAPTCHA_URL,
670
+ CURLOPT_POST => true,
671
+ CURLOPT_POSTFIELDS => array( 'secret' => $this->options['secretkey'], 'response' => $response ),
672
+ CURLOPT_RETURNTRANSFER => true,
673
+ ));
674
+
675
+ if (!$opt) {
676
+ cerber_admin_notice(__( 'ERROR:', 'wp-cerber' ) .' '. curl_error($curl));
677
+ curl_close($curl);
678
+ return false;
679
+ }
680
+
681
+ $result = curl_exec($curl);
682
+ if (!$result) {
683
+ cerber_admin_notice(__( 'ERROR:', 'wp-cerber' ) .' '. curl_error($curl));
684
+ $result = false;
685
+ }
686
+ curl_close($curl);
687
+
688
+ return $result;
689
+
690
+ }
691
+
692
+ final public function reCaptchaMsg($context = null){
693
+ return apply_filters( 'cerber_msg_recaptcha', __( 'Human verification failed. Please click the square box in the reCAPTCHA block below.', 'wp-cerber' ), $context);
694
+ }
695
+
696
+ final public function setLocked() {
697
+ if ( ! isset( $this->locked ) ) {
698
+ $this->locked = 1;
699
+ }
700
+ }
701
+
702
+ final public function isLocked() {
703
+ if ( ! empty( $this->locked ) ) {
704
+ return 1;
705
+ }
706
+ return 0;
707
+ }
708
+
709
+ final public function deleteGarbage() {
710
+ global $wpdb;
711
+ if ( $this->garbage ) {
712
+ return;
713
+ }
714
+ $wpdb->query( 'DELETE FROM ' . CERBER_BLOCKS_TABLE . ' WHERE block_until < ' . time() );
715
+ $this->garbage = true;
716
+ }
717
+ }
718
+
719
+ function cerber_init() {
720
+ static $done = false;
721
+
722
+ if ( $done ) {
723
+ return;
724
+ }
725
+
726
+ cerber_request_time();
727
+ cerber_upgrade_all();
728
+
729
+ global $wp_cerber;
730
+ $wp_cerber = get_wp_cerber();
731
+
732
+ cerber_beast();
733
+
734
+ $antibot = cerber_antibot_gene();
735
+ if ( $antibot && ! empty( $antibot[1] ) ) {
736
+ foreach ( $antibot[1] as $item ) {
737
+ setcookie( $item[0], $item[1], time() + 3600, COOKIEPATH );
738
+ }
739
+ }
740
+
741
+ //global $wp_cerber;
742
+ //$wp_cerber = get_wp_cerber();
743
+
744
+ // Redirection control: no default aliases for redirections
745
+ if ( crb_get_settings( 'noredirect' ) ) {
746
+ remove_action( 'template_redirect', 'wp_redirect_admin_locations', 1000 );
747
+ }
748
+
749
+ $done = true;
750
+ }
751
+
752
+ /**
753
+ * Returns correct WP_Cerber object
754
+ * Protects and sets global $wp_cerber to the proper object
755
+ *
756
+ * @return WP_Cerber
757
+ * @since 6.0
758
+ */
759
+ function get_wp_cerber(){
760
+ global $wp_cerber;
761
+ static $the_wp_cerber = null;
762
+
763
+ if ( ! isset( $the_wp_cerber ) ) {
764
+ $the_wp_cerber = new WP_Cerber();
765
+ }
766
+
767
+ $wp_cerber = $the_wp_cerber;
768
+
769
+ return $the_wp_cerber;
770
+ }
771
+
772
+ /**
773
+ *
774
+ * Initialize Cerber Security
775
+ *
776
+ */
777
+ add_action( 'plugins_loaded', function () {
778
+
779
+ get_wp_cerber();
780
+
781
+ load_plugin_textdomain( 'wp-cerber', false, basename( dirname( __FILE__ ) ) . '/languages' );
782
+
783
+ /* @since 5.8.8
784
+ if ( ! cerber_check_groove() && ! cerber_is_allowed() ) {
785
+ wp_clear_auth_cookie();
786
+ }*/
787
+
788
+ cerber_init_cron();
789
+
790
+ __('> > > Translator of WP Cerber? To get the PRO license for free, drop your contacts here: https://wpcerber.com/contact/','wp-cerber');
791
+
792
+ }, 1000 );
793
+
794
+ /**
795
+ * Some additional tasks...
796
+ *
797
+ */
798
+ add_action( 'shutdown', function () {
799
+ global $wpdb, $wp_cerber, $cerber_logged, $cerber_status;
800
+
801
+ if ( empty( $cerber_logged ) ) {
802
+ return;
803
+ }
804
+
805
+ // Multiple different malicious activities
806
+ $black = crb_get_activity_set('black');
807
+ $no_good = array_intersect( $black, $cerber_logged );
808
+ if ( ! empty( $no_good ) && cerber_is_allowed() ) {
809
+ $ip = $wp_cerber->getRemoteIp();
810
+ $in = implode( ',', $black );
811
+ $range = time() - 600;
812
+ $count = $wpdb->get_var( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE ip = "' . $ip . '" AND activity IN (' . $in . ') AND stamp > ' . $range );
813
+ if ( $count >= 3 ) {
814
+ cerber_soft_block_add( $ip, 7 );
815
+ $cerber_status = 18;
816
+ }
817
+ }
818
+
819
+ } );
820
+
821
+ /*
822
+ Display login form if Custom login URL has been requested
823
+
824
+ */
825
+ add_action( 'init', 'cerber_wp_login_page', 20 );
826
+ //add_action( 'setup_theme', 'cerber_wp_login_page' ); // @since 5.05
827
+ function cerber_wp_login_page() {
828
+ if ( $path = crb_get_settings( 'loginpath' ) ) {
829
+ if ( cerber_is_login_request() ) {
830
+ if ( ! defined( 'DONOTCACHEPAGE' ) ) {
831
+ define( 'DONOTCACHEPAGE', true ); // @since 5.7.6
832
+ }
833
+ require( ABSPATH . WP_LOGIN_SCRIPT ); // load default wp-login.php form
834
+ exit;
835
+ }
836
+ }
837
+ }
838
+
839
+ /**
840
+ * Check if the current HTTP request is a login/register/lost password page request
841
+ *
842
+ * @return bool
843
+ */
844
+ function cerber_is_login_request() {
845
+ if ( $path = crb_get_settings( 'loginpath' ) ) {
846
+ $request = $_SERVER['REQUEST_URI'];
847
+ if ( $pos = strpos( $request, '?' ) ) {
848
+ $request = substr( $request, 0, $pos - 1 ); // @since 4.8
849
+ }
850
+ $request = explode( '/', rtrim( $request, '/' ) );
851
+ $request = end( $request ); // @since 4.8
852
+ if ( $path == $request && ! cerber_is_rest_url() ) {
853
+ return true;
854
+ }
855
+ }
856
+ //elseif ( strtolower( cerber_parse_uri( true ) ) == WP_LOGIN_SCRIPT ) {
857
+ elseif ( cerber_get_uri_script() == WP_LOGIN_SCRIPT ) {
858
+ return true;
859
+ }
860
+
861
+ return false;
862
+ }
863
+
864
+ /*
865
+ Create message to show it above login form for any simply GET
866
+ */
867
+ add_action( 'login_head', 'cerber_login_head' );
868
+ function cerber_login_head() {
869
+ global $error, $wp_cerber;
870
+
871
+ if ( !$allowed = cerber_is_allowed() ) :
872
+ ?>
873
+ <style type="text/css" media="all">
874
+ #logidnform {
875
+ display: none;
876
+ }
877
+ </style>
878
+ <?php
879
+ endif;
880
+
881
+ $wp_cerber->reCaptcha( 'style' );
882
+
883
+ if ( !cerber_is_http_get() ) {
884
+ return;
885
+ }
886
+ if ( ! cerber_can_msg() ) {
887
+ return;
888
+ }
889
+ if ( ! $allowed ) {
890
+ $error = $wp_cerber->getErrorMsg();
891
+ }
892
+ elseif ( $msg = $wp_cerber->getRemainMsg() ) {
893
+ $error = $msg;
894
+ }
895
+ }
896
+
897
+ /**
898
+ * Control the process of authentication
899
+ *
900
+ * @since 2.9
901
+ *
902
+ */
903
+ remove_filter( 'authenticate', 'wp_authenticate_username_password', 20 );
904
+ remove_filter( 'authenticate', 'wp_authenticate_email_password', 20 );
905
+ add_filter( 'authenticate', 'cerber_auth_control', 20, 3 );
906
+ function cerber_auth_control( $user, $username, $password ) {
907
+ global $wp_cerber;
908
+
909
+ if ( ! $wp_cerber->reCaptchaValidate() ) {
910
+
911
+ return new WP_Error( 'incorrect_recaptcha',
912
+ '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
913
+ $wp_cerber->reCaptchaMsg('login'));
914
+ }
915
+
916
+ // Check for prohibited username
917
+ //if ( $wp_cerber->isProhibited( $username ) ) {
918
+ if ( cerber_is_prohibited( $username ) ) {
919
+ cerber_log( 52, $username );
920
+ cerber_block_add( null, 4, $username );
921
+
922
+ // Create with message that is identical default WP
923
+ return new WP_Error( 'incorrect_password', sprintf(
924
+ __( '<strong>ERROR</strong>: The password you entered for the username %s is incorrect.' ),
925
+ '<strong>' . $username . '</strong>'
926
+ ) );
927
+ }
928
+ /*
929
+ if ( lab_is_blocked($wp_cerber->getRemoteIp()) ) {
930
+
931
+ // Create with message which is identical default WP
932
+ return new WP_Error( 'incorrect_password', sprintf(
933
+ __( '<strong>ERROR</strong>: The password you entered for the username %s is incorrect.' ),
934
+ '<strong>' . $username . '</strong>'
935
+ ) );
936
+ }*/
937
+
938
+ $user = wp_authenticate_username_password( $user, $username, $password );
939
+ $user = wp_authenticate_email_password( $user, $username, $password );
940
+
941
+ // @since 4.18 it is replacement for 'wp_login_failed' action hook
942
+ // see WP function wp_authenticate()
943
+ $ignore_codes = array( 'empty_username', 'empty_password', 'cerber_denied' );
944
+ if ( is_wp_error( $user ) && ! in_array( $user->get_error_code(), $ignore_codes ) ) {
945
+ cerber_login_failed( $username );
946
+ }
947
+
948
+ return $user;
949
+ }
950
+
951
+ /*
952
+ Block authentication for an existing user if the remote IP is not allowed.
953
+ Invoking in the 'wp_authenticate_username_password()'
954
+ */
955
+ add_filter( 'wp_authenticate_user', 'cerber_stop_authentication', 9999, 2 ); // fires after user found, with 'authenticate' filter
956
+ function cerber_stop_authentication( $user, $password ) {
957
+ global $wp_cerber, $cerber_status;
958
+
959
+ $deny = false;
960
+
961
+ if ( ! cerber_is_allowed() ) {
962
+ $deny = true;
963
+ }
964
+ elseif ( ! cerber_geo_allowed( 'geo_login' ) ) {
965
+ $cerber_status = 16;
966
+ $deny = true;
967
+ }
968
+ elseif ( lab_is_blocked( $wp_cerber->getRemoteIp() ) ) {
969
+ $cerber_status = 15;
970
+ $deny = true;
971
+ }
972
+
973
+ if ( $deny ) {
974
+ status_header( 403 );
975
+ $error = new WP_Error();
976
+ $error->add( 'cerber_wp_error', $wp_cerber->getErrorMsg() );
977
+
978
+ return $error;
979
+ }
980
+
981
+ return $user;
982
+ }
983
+
984
+ /*
985
+ * Handler for failed login attempts
986
+ *
987
+ */
988
+ //add_action( 'wp_login_failed', 'cerber_login_failed' ); // @since 4.18
989
+ function cerber_login_failed( $user_login ) {
990
+ global $wpdb, $wp_cerber, $cerber_status;
991
+ static $is_processed = false;
992
+
993
+ if ( $is_processed ) return;
994
+ $is_processed = true;
995
+
996
+ $ip = $wp_cerber->getRemoteIp();
997
+ $acl = cerber_acl_check( $ip );
998
+ if ( ! cerber_get_user( $user_login ) ) {
999
+ $no_user = true;
1000
+ }
1001
+ else {
1002
+ $no_user = false;
1003
+ }
1004
+
1005
+ //cerber_failed_work($ip, $acl, $no_user, $user_login);
1006
+
1007
+ //if ( ! $wp_cerber->isProcessed() ) {
1008
+ //if ( ! cerber_get_user( $user_login ) ) {
1009
+ // $no_user = true;
1010
+ //}
1011
+
1012
+ $ac = 7;
1013
+
1014
+ if ( $no_user ) {
1015
+ $ac = 51;
1016
+ }
1017
+ elseif ( ! cerber_is_allowed( $ip ) || $cerber_status == 15 || $cerber_status == 16 ) { // TODO should be refactored together with cerber_stop_authentication
1018
+ $ac = 53;
1019
+ }
1020
+ /*
1021
+ elseif ( $acl == 'B' ) {
1022
+ $ac = 14;
1023
+ }
1024
+ elseif ( lab_is_blocked($ip, false) ) {
1025
+ $ac = 53;
1026
+ }
1027
+ else {
1028
+ $ac = 53;
1029
+ }*/
1030
+
1031
+ cerber_log( $ac, $user_login );
1032
+
1033
+ //}
1034
+
1035
+
1036
+ // White? Stop further actions.
1037
+ if ( $acl == 'W' && !crb_get_settings( 'limitwhite' )) {
1038
+ return;
1039
+ }
1040
+
1041
+ if ( crb_get_settings( 'usefile' ) ) {
1042
+ cerber_file_log( $user_login, $ip );
1043
+ }
1044
+
1045
+ if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) { // Needs additional researching and, maybe, refactoring
1046
+ status_header( 403 );
1047
+ }
1048
+
1049
+ // Blacklisted? No more actions are needed.
1050
+ if ( $acl == 'B' ) {
1051
+ return;
1052
+ }
1053
+
1054
+ // Must the Citadel mode be activated?
1055
+ if ( $wp_cerber->getSettings( 'ciperiod' ) && ! cerber_is_citadel() ) {
1056
+ $range = time() - $wp_cerber->getSettings( 'ciperiod' ) * 60;
1057
+ $lockouts = $wpdb->get_var( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE activity IN (7,51,52) AND stamp > ' . $range );
1058
+ if ( $lockouts >= $wp_cerber->getSettings( 'cilimit' ) ) {
1059
+ cerber_enable_citadel();
1060
+ }
1061
+ }
1062
+
1063
+ if ( $no_user && $wp_cerber->getSettings( 'nonusers' ) ) {
1064
+ cerber_block_add( $ip, 3, $user_login); // @since 5.7
1065
+ }
1066
+ elseif ( cerber_get_remain_count($ip, false) < 1 ) { //Limit on the number of login attempts is reached
1067
+ cerber_block_add( $ip, 1, '', null, false);
1068
+ }
1069
+
1070
+ }
1071
+
1072
+ /**
1073
+ * Do the work with failed/blocked attempt
1074
+ *
1075
+ * @param $ip
1076
+ * @param $acl
1077
+ * @param $user_login
1078
+ */
1079
+ function cerber_failed_work($ip, $acl, $no_user, $user_login){
1080
+ global $wpdb, $wp_cerber;
1081
+
1082
+ // White? Stop further actions.
1083
+ if ( $acl == 'W' && !$wp_cerber->getSettings( 'limitwhite' )) {
1084
+ return;
1085
+ }
1086
+
1087
+ if ( $wp_cerber->getSettings( 'usefile' ) ) {
1088
+ cerber_file_log( $user_login, $ip );
1089
+ }
1090
+
1091
+ if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) { // Needs additional researching and, maybe, refactoring
1092
+ status_header( 403 );
1093
+ }
1094
+
1095
+ // Blacklisted? No more actions are needed.
1096
+ if ( $acl == 'B' ) {
1097
+ return;
1098
+ }
1099
+
1100
+ // Must the Citadel mode be activated?
1101
+ if ( $wp_cerber->getSettings( 'ciperiod' ) && ! cerber_is_citadel() ) {
1102
+ $range = time() - $wp_cerber->getSettings( 'ciperiod' ) * 60;
1103
+ $lockouts = $wpdb->get_var( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE activity IN (7,51,52) AND stamp > ' . $range );
1104
+ if ( $lockouts >= $wp_cerber->getSettings( 'cilimit' ) ) {
1105
+ cerber_enable_citadel();
1106
+ }
1107
+ }
1108
+
1109
+ if ( $no_user && $wp_cerber->getSettings( 'nonusers' ) ) {
1110
+ cerber_block_add( $ip, 3, $user_login );
1111
+ }
1112
+ elseif ( cerber_get_remain_count($ip, false) <= 1 ) { //Limit on the number of login attempts is reached
1113
+ cerber_block_add( $ip, 1, '', null, false);
1114
+ }
1115
+ }
1116
+
1117
+ // Registration -----------------------------------------------------------------------
1118
+
1119
+ function cerber_is_registration_prohibited( $sanitized_user_login ) {
1120
+ global $wp_cerber, $cerber_status;
1121
+
1122
+ $code = null;
1123
+ $msg = null;
1124
+
1125
+ if (crb_is_reg_limit_reached()){
1126
+ $cerber_status = 17;
1127
+ cerber_log(54);
1128
+ $code = 'ip_denied';
1129
+ $msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
1130
+ apply_filters( 'cerber_msg_denied', __( 'You are not allowed to register.', 'wp-cerber' ), 'register' );
1131
+ }
1132
+ elseif ( cerber_is_bot('botsreg') ) {
1133
+ cerber_log(54); // TODO should be separate code to detect bot activity?
1134
+ $code = 'bot_detected';
1135
+ $msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
1136
+ apply_filters( 'cerber_msg_denied', __( 'You are not allowed to register.', 'wp-cerber' ), 'register' );
1137
+ }
1138
+ elseif ( ! $wp_cerber->reCaptchaValidate() ) {
1139
+ $code = 'incorrect_recaptcha';
1140
+ $msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
1141
+ $wp_cerber->reCaptchaMsg('register');
1142
+ }
1143
+ elseif ( cerber_is_prohibited( $sanitized_user_login ) ) {
1144
+ $code = 'prohibited_login';
1145
+ $msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
1146
+ apply_filters( 'cerber_msg_prohibited', __( 'Username is not allowed. Please choose another one.', 'wp-cerber' ), 'register' );
1147
+ }
1148
+ elseif ( !cerber_is_allowed() || lab_is_blocked($wp_cerber->getRemoteIp()) ) {
1149
+ cerber_log(54);
1150
+ $code = 'ip_denied';
1151
+ $msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
1152
+ apply_filters( 'cerber_msg_denied', __( 'You are not allowed to register.', 'wp-cerber' ), 'register' );
1153
+ }
1154
+ elseif ( ! cerber_geo_allowed( 'geo_register' ) ) {
1155
+ $cerber_status = 16; // TODO: refactor cerber_log, include this status as a second parameter
1156
+ cerber_log(54); // TODO should be separate code?
1157
+ $code = 'country_denied';
1158
+ $msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
1159
+ apply_filters( 'cerber_msg_denied', __( 'You are not allowed to register.', 'wp-cerber' ), 'register' );
1160
+ }
1161
+
1162
+ if ( $code ) {
1163
+ return array( $code, $msg );
1164
+ }
1165
+
1166
+ return null;
1167
+ }
1168
+
1169
+ /**
1170
+ * Limit on user registrations per IP
1171
+ *
1172
+ * @return bool
1173
+ */
1174
+ function crb_is_reg_limit_reached() {
1175
+ global $wpdb, $wp_cerber;
1176
+
1177
+ if ( ! $wp_cerber->getSettings( 'reglimit_min' ) || ! $wp_cerber->getSettings( 'reglimit_num' ) ) {
1178
+ return false;
1179
+ }
1180
+
1181
+ if ( crb_acl_is_white() ) {
1182
+ return false;
1183
+ }
1184
+
1185
+ $ip = $wp_cerber->getRemoteIp();
1186
+ $stamp = absint( time() - 60 * $wp_cerber->getSettings( 'reglimit_min' ) );
1187
+ $count = $wpdb->get_var( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE ip = "' . $ip . '" AND activity = 2 AND stamp > ' . $stamp );
1188
+ if ( $count > $wp_cerber->getSettings( 'reglimit_num' ) ) {
1189
+ lab_save_push( $ip, 344, '' );
1190
+ return true;
1191
+ }
1192
+
1193
+ return false;
1194
+ }
1195
+
1196
+ // Fires in register_new_user()
1197
+ add_filter( 'registration_errors', 'cerber_pre_new_user', 10, 3 );
1198
+ function cerber_pre_new_user( $errors, $sanitized_user_login, $user_email ) {
1199
+ global $wp_cerber, $cerber_status;
1200
+
1201
+ $prohibited = cerber_is_registration_prohibited( $sanitized_user_login );
1202
+
1203
+ if ($prohibited){
1204
+ return new WP_Error($prohibited[0], $prohibited[1]);
1205
+ }
1206
+
1207
+ return $errors;
1208
+ }
1209
+
1210
+ // @since 5.3
1211
+ // Fires in wp_insert_user()
1212
+ add_filter( 'pre_user_login', function ( $sanitized_user_login ) {
1213
+
1214
+ if ( cerber_is_registration_prohibited( $sanitized_user_login ) ) {
1215
+ return null;
1216
+ }
1217
+
1218
+ /*
1219
+ if ( ! cerber_is_allowed() ) {
1220
+ cerber_log( 54 );
1221
+
1222
+ return null;
1223
+ }
1224
+ if ( ! cerber_geo_allowed( 'geo_register' ) ) {
1225
+ $cerber_status = 16;
1226
+ cerber_log( 54 );
1227
+
1228
+ return null;
1229
+ }
1230
+ */
1231
+ return $sanitized_user_login;
1232
+ }, 9999 );
1233
+
1234
+ // Filter out prohibited usernames
1235
+ add_filter( 'illegal_user_logins', function () {
1236
+ return (array) crb_get_settings( 'prohibited' );
1237
+ }, 9999 );
1238
+
1239
+ add_filter( 'option_users_can_register', function ( $value ) {
1240
+ //if ( ! cerber_is_allowed() || !cerber_geo_allowed( 'geo_register' )) {
1241
+ if ( ! cerber_is_allowed() || crb_is_reg_limit_reached() ) {
1242
+ return false;
1243
+ }
1244
+
1245
+ return $value;
1246
+ }, 9999 );
1247
+
1248
+ // Lost password form --------------------------------------------------------------------
1249
+
1250
+ /**
1251
+ * Validate reCAPTCHA for the WordPress lost password form
1252
+ */
1253
+ add_action( 'login_form_' . 'lostpassword', 'cerber_lost_captcha' );
1254
+ function cerber_lost_captcha() {
1255
+ global $wp_cerber, $cerber_lost;
1256
+ if ( ! $wp_cerber->reCaptchaValidate() ) {
1257
+ $_POST['user_login'] = null; // workaround due to lack of any way to control lost password form
1258
+ $cerber_lost = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' . $wp_cerber->reCaptchaMsg('lostpassword');
1259
+ }
1260
+ }
1261
+ /**
1262
+ * Display message on the WordPress lost password form screen
1263
+ */
1264
+ add_action( 'lostpassword_form', 'cerber_lost_show_msg' );
1265
+ function cerber_lost_show_msg() {
1266
+ global $cerber_lost;
1267
+ if ( ! $cerber_lost ) {
1268
+ return;
1269
+ }
1270
+ ?>
1271
+ <script type="text/javascript">
1272
+ //document.getElementById('login_error').style.visibility = "hidden";
1273
+ document.getElementById('login_error').innerHTML = "<?php echo $cerber_lost; ?>";
1274
+ </script>
1275
+ <?php
1276
+ }
1277
+
1278
+
1279
+ // Comments (commenting) section ----------------------------------------------------------
1280
+
1281
+ /**
1282
+ * If a comment must be marked as spam
1283
+ *
1284
+ */
1285
+ add_filter( 'pre_comment_approved', function ( $approved, $commentdata ) {
1286
+ if ( 1 == crb_get_settings( 'spamcomm' ) && ! cerber_is_comment_allowed() ) {
1287
+ $approved = 'spam';
1288
+ }
1289
+
1290
+ return $approved;
1291
+ }, 10, 2 );
1292
+
1293
+ /**
1294
+ * If a comment must be denied
1295
+ *
1296
+ */
1297
+ add_action( 'pre_comment_on_post', function ( $comment_post_ID ) {
1298
+ global $cerber_status;
1299
+
1300
+ $deny = false;
1301
+
1302
+ if ( 1 != crb_get_settings( 'spamcomm' ) && ! cerber_is_comment_allowed() ) {
1303
+ $deny = true;
1304
+ }
1305
+ elseif ( ! cerber_geo_allowed( 'geo_comment' ) ) {
1306
+ $cerber_status = 16;
1307
+ cerber_log(19);
1308
+ $deny = true;
1309
+ }
1310
+
1311
+ if ( $deny ) {
1312
+ setcookie( 'cerber-post-id', $comment_post_ID, time() + 60, '/' );
1313
+ $comments = get_comments( array( 'number' => '1', 'post_id' => $comment_post_ID ) );
1314
+ if ( $comments ) {
1315
+ $loc = get_comment_link( $comments[0]->comment_ID );
1316
+ } else {
1317
+ $loc = get_permalink( $comment_post_ID ) . '#cerber-recaptcha-msg';
1318
+ }
1319
+ wp_safe_redirect( $loc );
1320
+ exit;
1321
+ }
1322
+
1323
+ } );
1324
+
1325
+ /**
1326
+ * If submit comments via REST API is not allowed
1327
+ *
1328
+ */
1329
+ add_filter( 'rest_allow_anonymous_comments', function ( $allowed, $request ) {
1330
+ global $wp_cerber, $cerber_status;
1331
+
1332
+ if ( ! cerber_is_allowed() ) {
1333
+ $allowed = false;
1334
+ }
1335
+ if ( ! cerber_geo_allowed( 'geo_comment' ) ) {
1336
+ ceber_log(19);
1337
+ $cerber_status = 16;
1338
+ $allowed = false;
1339
+ }
1340
+ elseif ( lab_is_blocked( $wp_cerber->getRemoteIp() ) ) {
1341
+ $allowed = false;
1342
+ }
1343
+
1344
+ return $allowed;
1345
+ }, 10, 2 );
1346
+
1347
+ /**
1348
+ * Check if a submitted comment is allowed
1349
+ *
1350
+ * @return bool
1351
+ */
1352
+ function cerber_is_comment_allowed(){
1353
+ global $wp_cerber;
1354
+
1355
+ if (is_admin()) return true;
1356
+
1357
+ $deny = null;
1358
+
1359
+ if ( ! cerber_is_allowed() ) {
1360
+ $deny = 19;
1361
+ }
1362
+ elseif ( cerber_is_bot('botscomm') ) {
1363
+ $remain = cerber_get_remain_count( null , true, 16, 3, 60);
1364
+ if ($remain < 1) cerber_block_add( null, 6, '', 60 );
1365
+ $deny = 16;
1366
+ }
1367
+ elseif ( ! $wp_cerber->reCaptchaValidate( 'comment' , true ) ) {
1368
+ $deny = 16;
1369
+ }
1370
+ elseif ( lab_is_blocked( $wp_cerber->getRemoteIp() ) ) {
1371
+ $deny = 19;
1372
+ }
1373
+
1374
+ if ( $deny ) {
1375
+ cerber_log( $deny );
1376
+ $ret = false;
1377
+ }
1378
+ else {
1379
+ $ret = true;
1380
+ }
1381
+
1382
+ return $ret;
1383
+ }
1384
+
1385
+ /**
1386
+ * Showing reCAPTCHA widget.
1387
+ * Displaying error message on the comment form for a human.
1388
+ *
1389
+ */
1390
+ add_filter( 'comment_form_submit_field', function ( $value ) {
1391
+ global $wp_cerber, $post;
1392
+
1393
+ if ( ! empty( $_COOKIE["cerber-post-id"] ) && absint( $_COOKIE["cerber-post-id"] ) == $post->ID ) {
1394
+ //echo '<div id="cerber-recaptcha-msg">' . __( 'ERROR:', 'wp-cerber' ) . ' ' . $wp_cerber->reCaptchaMsg( 'comment' ) . '</div>';
1395
+ echo '<div id="cerber-recaptcha-msg">' . __( 'ERROR:', 'wp-cerber' ) . ' ' . __('Sorry, human verification failed.') . '</div>';
1396
+ echo '<script type="text/javascript">document.cookie = "cerber-post-id=0;path=/";</script>';
1397
+ }
1398
+
1399
+ $au = $wp_cerber->getSettings( 'recapcomauth' );
1400
+ if ( ! $au || ( $au && ! is_user_logged_in() ) ) {
1401
+ $wp_cerber->reCaptcha( 'widget', 'recapcom' );
1402
+ }
1403
+
1404
+ return $value;
1405
+ } );
1406
+
1407
+
1408
+ // Messages ----------------------------------------------------------------------
1409
+
1410
+ /**
1411
+ * Replace ANY system messages or add notify message above login form if IP is not allowed (blocked or locked out)
1412
+ */
1413
+ add_filter( 'login_errors', 'cerber_login_form_msg' ); // hook on POST if credentials was wrong
1414
+ function cerber_login_form_msg( $errors ) {
1415
+ global $error, $wp_cerber;
1416
+ if ( cerber_can_msg() ) {
1417
+ if ( ! cerber_is_allowed() ) {
1418
+ $errors = $wp_cerber->getErrorMsg();
1419
+ }
1420
+ elseif ( ! $error && ( $msg = $wp_cerber->getRemainMsg() ) ) {
1421
+ $errors .= '<p>' . $msg;
1422
+ }
1423
+ }
1424
+
1425
+ return $errors;
1426
+ }
1427
+
1428
+ add_filter( 'shake_error_codes', 'cerber_login_failure_shake' ); // Shake it, baby!
1429
+ function cerber_login_failure_shake( $shake_error_codes ) {
1430
+ $shake_error_codes[] = 'cerber_wp_error';
1431
+
1432
+ return $shake_error_codes;
1433
+ }
1434
+
1435
+ /*
1436
+ Replace default login/logout URL with Custom login page URL
1437
+ */
1438
+ add_filter( 'site_url', 'cerber_login_logout', 9999, 4 );
1439
+ add_filter( 'network_site_url', 'cerber_login_logout', 9999, 3 );
1440
+ function cerber_login_logout( $url, $path, $scheme, $blog_id = 0 ) { // $blog_id only for 'site_url'
1441
+ global $wp_cerber;
1442
+ if ( $login_path = $wp_cerber->getSettings( 'loginpath' ) ) {
1443
+ $url = str_replace( WP_LOGIN_SCRIPT, $login_path . '/', $url );
1444
+ }
1445
+
1446
+ return $url;
1447
+ }
1448
+
1449
+ /*
1450
+ Replace default logout redirect URL with Custom login page URL
1451
+ */
1452
+ add_filter( 'wp_redirect', 'cerber_login_redirect', 9999, 2 );
1453
+ function cerber_login_redirect( $location, $status ) {
1454
+ global $wp_cerber;
1455
+ if ( ($path = $wp_cerber->getSettings( 'loginpath' )) && ( 0 === strpos( $location, WP_LOGIN_SCRIPT . '?' ) ) ) {
1456
+ $loc = explode( '?', $location );
1457
+ $location = get_home_url() . '/' . $path . '/?' . $loc[1];
1458
+ }
1459
+
1460
+ return $location;
1461
+ }
1462
+
1463
+ // Access control ========================================================================================
1464
+
1465
+ add_action( 'init', function () {
1466
+ if ( crb_get_settings( 'adminphp' ) && ! is_user_logged_in() ) {
1467
+ define( 'CONCATENATE_SCRIPTS', false );
1468
+ }
1469
+ cerber_access_control();
1470
+ cerber_antibot_control();
1471
+ }, 0 );
1472
+
1473
+ /**
1474
+ * Restrict access to vital parts of WP
1475
+ *
1476
+ */
1477
+ function cerber_access_control() {
1478
+ global $wp_cerber, $cerber_status;
1479
+
1480
+ if ( is_admin() ) {
1481
+ return;
1482
+ }
1483
+
1484
+ // IPs from the White List are allowed
1485
+ $acl = cerber_acl_check();
1486
+ if ( $acl == 'W' ) {
1487
+ return;
1488
+ }
1489
+
1490
+ //if ( $acl == 'B' || cerber_block_check() ) {
1491
+ if ( $acl == 'B' || !cerber_is_allowed() ) { // @since 5.8.2
1492
+ $deny = true;
1493
+ }
1494
+ else {
1495
+ $deny = false;
1496
+ }
1497
+
1498
+ //$opt = $wp_cerber->getSettings();
1499
+ $opt = crb_get_settings();
1500
+ /*
1501
+ $script = cerber_last_uri();
1502
+ if ( substr( $script, - 4 ) != '.php' ) {
1503
+ $script .= '.php'; // Apache MultiViews enabled?
1504
+ }
1505
+
1506
+ if ( $script ) {
1507
+ if ( $script == WP_LOGIN_SCRIPT || $script == WP_SIGNUP_SCRIPT || ( $script == WP_REG_URI && ! get_option( 'users_can_register' ) ) ) { // no direct access
1508
+ if ( !empty( $opt['wplogin'] ) ) {
1509
+ cerber_log( 50 );
1510
+ cerber_soft_block_add( $wp_cerber->getRemoteIp(), 2, $script );
1511
+ cerber_404_page();
1512
+ }
1513
+ if ( $deny || !empty( $opt['loginnowp'] ) ) {
1514
+ cerber_log( 50 );
1515
+ cerber_404_page();
1516
+ }
1517
+ }
1518
+ elseif ( $script == WP_XMLRPC_SCRIPT || $script == WP_TRACKBACK_SCRIPT ) { // no direct access
1519
+ if ( $deny || ! empty( $opt['xmlrpc'] ) ) {
1520
+ cerber_log( 50 ); // @since 5.21
1521
+ cerber_404_page();
1522
+ }
1523
+ elseif ( !cerber_geo_allowed( 'geo_xmlrpc' ) ) {
1524
+ $cerber_status = 16;
1525
+ cerber_log( 71 );
1526
+ cerber_404_page();
1527
+ }
1528
+ }
1529
+ }
1530
+ */
1531
+ $wp_cerber = get_wp_cerber();
1532
+ if ( $wp_cerber->isURIProhibited() ) {
1533
+ cerber_404_page();
1534
+ }
1535
+
1536
+ // REST API
1537
+ if ( $deny ) {
1538
+ cerber_block_rest();
1539
+ }
1540
+ elseif ( cerber_is_rest_url() ) {
1541
+ $rest_allowed = true;
1542
+ if ( ! empty( $opt['norest'] ) ) {
1543
+ $rest_allowed = false;
1544
+ if ( $opt['restauth'] && is_user_logged_in() ) {
1545
+ $rest_allowed = true;
1546
+ }
1547
+ elseif ( cerber_is_route_allowed() ) {
1548
+ $rest_allowed = true;
1549
+ }
1550
+ }
1551
+ /*
1552
+ $rest_allowed = true;
1553
+ if ( ! empty( $opt['norest'] ) && ! cerber_is_route_allowed() ) {
1554
+ $rest_allowed = false;
1555
+ }*/
1556
+ if ( $rest_allowed && cerber_is_route_blocked() ) {
1557
+ $rest_allowed = false;
1558
+ }
1559
+ if ( $rest_allowed && ! cerber_geo_allowed( 'geo_restapi' ) ) {
1560
+ $rest_allowed = false;
1561
+ $cerber_status = 16;
1562
+ }
1563
+ if ( ! $rest_allowed ) {
1564
+ cerber_block_rest();
1565
+ }
1566
+ }
1567
+
1568
+ // Some XML-RPC stuff
1569
+ if ( $deny || ! empty( $opt['xmlrpc'] ) ) {
1570
+ add_filter( 'xmlrpc_enabled', '__return_false' );
1571
+ add_filter( 'pings_open', '__return_false' );
1572
+ add_filter( 'bloginfo_url', 'cerber_pingback_url', 10, 2 );
1573
+ remove_action( 'wp_head', 'rsd_link', 10 );
1574
+ remove_action( 'wp_head', 'wlwmanifest_link', 10 );
1575
+ }
1576
+
1577
+ // Feeds
1578
+ if ( $deny || ! empty( $opt['nofeeds'] ) ) {
1579
+ remove_action( 'wp_head', 'feed_links', 2 );
1580
+ remove_action( 'wp_head', 'feed_links_extra', 3 );
1581
+
1582
+ remove_action( 'do_feed_rdf', 'do_feed_rdf', 10 );
1583
+ remove_action( 'do_feed_rss', 'do_feed_rss', 10 );
1584
+ remove_action( 'do_feed_rss2', 'do_feed_rss2', 10 );
1585
+ remove_action( 'do_feed_atom', 'do_feed_atom', 10 );
1586
+ remove_action( 'do_pings', 'do_all_pings', 10 );
1587
+
1588
+ add_action( 'do_feed_rdf', 'cerber_404_page', 1 );
1589
+ add_action( 'do_feed_rss', 'cerber_404_page', 1 );
1590
+ add_action( 'do_feed_rss2', 'cerber_404_page', 1 );
1591
+ add_action( 'do_feed_atom', 'cerber_404_page', 1 );
1592
+ add_action( 'do_feed_rss2_comments', 'cerber_404_page', 1 );
1593
+ add_action( 'do_feed_atom_comments', 'cerber_404_page', 1 );
1594
+ }
1595
+ }
1596
+
1597
+ /**
1598
+ * Antispam & Antibot for forms
1599
+ *
1600
+ */
1601
+ function cerber_antibot_control(){
1602
+ global $cerber_status;
1603
+
1604
+ if ( !cerber_is_http_post() || cerber_acl_check( null, 'W' ) ) {
1605
+ return;
1606
+ }
1607
+
1608
+ if ( !cerber_antibot_enabled('botsany') && !cerber_geo_rules('geo_submit')) {
1609
+ return;
1610
+ }
1611
+
1612
+ // Exceptions -----------------------------------------------------------------------
1613
+
1614
+ if ( cerber_is_antibot_exception() ) {
1615
+ return;
1616
+ }
1617
+
1618
+ // Let's make the checks
1619
+
1620
+ $deny = false;
1621
+
1622
+ if ( ! cerber_is_allowed() ) {
1623
+ $deny = true;
1624
+ cerber_log(18);
1625
+ }
1626
+ elseif ( cerber_is_bot( 'botsany' ) ) {
1627
+ $deny = true;
1628
+ cerber_log( 17 );
1629
+ }
1630
+ elseif ( !cerber_geo_allowed( 'geo_submit' ) ) {
1631
+ $deny = true;
1632
+ $cerber_status = 16; // TODO: refactor cerber_log, include this status as a second parameter
1633
+ cerber_log( 18 );
1634
+ }
1635
+ elseif ( lab_is_blocked( null, true ) ) {
1636
+ $deny = true;
1637
+ $cerber_status = 18;
1638
+ cerber_log( 18 );
1639
+ }
1640
+
1641
+ if ($deny){
1642
+ cerber_forbidden_page();
1643
+ }
1644
+
1645
+ }
1646
+
1647
+ /**
1648
+ * Exception for POST query control
1649
+ *
1650
+ * @return bool
1651
+ */
1652
+ function cerber_is_antibot_exception(){
1653
+
1654
+ if ( defined( 'DOING_CRON' ) && DOING_CRON ) {
1655
+ return true;
1656
+ }
1657
+
1658
+ // Admin || AJAX requests by unauthorized users
1659
+ if ( is_admin() ) {
1660
+ if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
1661
+ if (is_user_logged_in()) {
1662
+ return true;
1663
+ }
1664
+ }
1665
+ else {
1666
+ return true;
1667
+ }
1668
+ }
1669
+
1670
+ // Standard WordPress Comments
1671
+ if ( 0 === strpos( trim( $_SERVER['REQUEST_URI'], '/' ), 'wp-comments-post.php' ) ) {
1672
+ return true;
1673
+ }
1674
+
1675
+ // XML-RPC
1676
+ if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
1677
+ return true;
1678
+ }
1679
+
1680
+ // Trackback
1681
+ if ( is_trackback() ) {
1682
+ return true;
1683
+ }
1684
+
1685
+ // Login page
1686
+ if ( cerber_is_login_request() ) {
1687
+ return true;
1688
+ }
1689
+
1690
+ // REST API (except Contact Form 7 submission)
1691
+ if ( cerber_is_rest_url() ) {
1692
+ if ( false === strpos( $_SERVER['REQUEST_URI'], 'contact-form-7' ) ) {
1693
+ return true;
1694
+ }
1695
+ }
1696
+
1697
+ return false;
1698
+ }
1699
+
1700
+ /*
1701
+ * Disable pingback URL (hide from HEAD)
1702
+ */
1703
+ function cerber_pingback_url( $output, $show ) {
1704
+ if ( $show == 'pingback_url' ) {
1705
+ $output = '';
1706
+ }
1707
+
1708
+ return $output;
1709
+ }
1710
+
1711
+ /**
1712
+ * Disable REST API
1713
+ *
1714
+ */
1715
+ function cerber_block_rest() {
1716
+ global $wp_version;
1717
+ // OLD WP
1718
+ add_filter( 'json_enabled', '__return_false' );
1719
+ add_filter( 'json_jsonp_enabled', '__return_false' );
1720
+ // WP 4.4, deprecated since 4.7
1721
+ if ( version_compare( $wp_version, '4.7', '<' ) ) {
1722
+ add_filter( 'rest_enabled', '__return_false', 9999 );
1723
+ }
1724
+ // WP 4.7
1725
+ add_filter( 'rest_jsonp_enabled', '__return_false' );
1726
+ // Links
1727
+ remove_action( 'wp_head', 'rest_output_link_wp_head', 10 );
1728
+ remove_action( 'template_redirect', 'rest_output_link_header', 11 );
1729
+ // Default REST API hooks from default-filters.php
1730
+ remove_action( 'init', 'rest_api_init' );
1731
+ remove_action( 'rest_api_init', 'rest_api_default_filters', 10 );
1732
+ remove_action( 'rest_api_init', 'register_initial_settings', 10 );
1733
+ remove_action( 'rest_api_init', 'create_initial_rest_routes', 99 );
1734
+ remove_action( 'parse_request', 'rest_api_loaded' );
1735
+
1736
+ if ( cerber_is_rest_url() ) {
1737
+ cerber_log( 70 );
1738
+ //cerber_404_page();
1739
+ cerber_forbidden_page(); // @since 6.0
1740
+ }
1741
+ }
1742
+
1743
+ /*
1744
+ * Redirection control: standard admin/login redirections
1745
+ *
1746
+ */
1747
+ add_filter( 'wp_redirect', 'cerber_no_redirect', 10, 2 );
1748
+ function cerber_no_redirect( $location, $status ) {
1749
+ global $current_user, $wp_cerber;
1750
+ if ( (!$current_user || $current_user->ID == 0) && $wp_cerber->getSettings( 'noredirect' ) ) {
1751
+ $str = urlencode( '/wp-admin/' );
1752
+ $rdr = explode('redirect_to=',$location);
1753
+ if ( isset($rdr[1]) && strpos( $rdr[1], $str ) ) {
1754
+ cerber_404_page();
1755
+ }
1756
+ }
1757
+
1758
+ return $location;
1759
+ }
1760
+
1761
+ /*
1762
+ * Stop user enumeration
1763
+ *
1764
+ */
1765
+ add_action( 'template_redirect', 'cerber_canonical', 1 );
1766
+ function cerber_canonical() {
1767
+ if ( crb_get_settings( 'stopenum' ) ) {
1768
+ if ( ! is_admin() && ! empty( $_GET['author'] ) ) {
1769
+ cerber_404_page();
1770
+ }
1771
+ }
1772
+ }
1773
+ /*
1774
+ if ( $wp_cerber->getSettings( 'hashauthor' ) ) {
1775
+ add_filter( 'request',
1776
+ function ( $vars ) {
1777
+ if (isset($vars['author_name']) && !is_admin()) {
1778
+ $vars['author_name'] = '><';
1779
+ }
1780
+
1781
+ return $vars;
1782
+ } );
1783
+ }
1784
+ */
1785
+
1786
+ /*
1787
+ Can login form message be shown?
1788
+ */
1789
+ function cerber_can_msg() {
1790
+ if ( ! isset( $_REQUEST['action'] ) ) {
1791
+ return true;
1792
+ }
1793
+ if ( $_REQUEST['action'] == 'login' ) {
1794
+ return true;
1795
+ }
1796
+
1797
+ return false;
1798
+ //if ( !in_array( $action, array( 'postpass', 'logout', 'lostpassword', 'retrievepassword', 'resetpass', 'rp', 'register', 'login' );
1799
+ }
1800
+
1801
+
1802
+ // Cookies ---------------------------------------------------------------------------------
1803
+ /*
1804
+ Mark user with Cerber Groove
1805
+ @since 1.3
1806
+ */
1807
+ add_action( 'auth_cookie_valid', 'cerber_cookie1', 10, 2 );
1808
+ function cerber_cookie1( $cookie_elements = null, $user = null ) {
1809
+ global $current_user;
1810
+ if ( ! $user ) {
1811
+ $user = wp_get_current_user();
1812
+ }
1813
+ $expire = time() + apply_filters( 'auth_cookie_expiration', 14 * 24 * 3600, $user->ID, true ) + ( 24 * 3600 );
1814
+ cerber_set_groove( $expire );
1815
+ }
1816
+
1817
+ /*
1818
+ Mark switched user with Cerber Groove
1819
+ @since 1.6
1820
+ */
1821
+ add_action( 'set_logged_in_cookie', 'cerber_cookie2', 10, 5 );
1822
+ function cerber_cookie2( $logged_in_cookie, $expire, $expiration, $user_id, $logged_in ) {
1823
+ cerber_set_groove( $expire );
1824
+ }
1825
+
1826
+ /*
1827
+ Track BAD cookies with non-existence user or bad password (hash)
1828
+ */
1829
+ add_action( 'auth_cookie_bad_username', 'cerber_cookie_bad' );
1830
+ add_action( 'auth_cookie_bad_hash', 'cerber_cookie_bad' );
1831
+ function cerber_cookie_bad( $cookie_elements ) {
1832
+ cerber_login_failed( $cookie_elements['username'] );
1833
+ }
1834
+
1835
+ /**
1836
+ * Is bot detection engine enabled in a given rule_id
1837
+ *
1838
+ * @param $location string|array ID of the location
1839
+ *
1840
+ * @return bool true if enabled
1841
+ */
1842
+ function cerber_antibot_enabled( $location ) {
1843
+
1844
+ if ( crb_get_settings( 'botsnoauth' ) && is_user_logged_in() ) {
1845
+ return false;
1846
+ }
1847
+
1848
+ if ( is_array( $location ) ) {
1849
+ foreach ( $location as $loc ) {
1850
+ if ( crb_get_settings( $loc ) ) {
1851
+ return true;
1852
+ }
1853
+ }
1854
+ }
1855
+ else {
1856
+ if ( crb_get_settings( $location ) ) {
1857
+ return true;
1858
+ }
1859
+ }
1860
+
1861
+ return false;
1862
+ }
1863
+
1864
+ /**
1865
+ * Print out the antibot/antispam jQuery code
1866
+ *
1867
+ * @param $location string|array Location (setting)
1868
+ */
1869
+ function cerber_antibot_code($location) {
1870
+ if ( ! cerber_antibot_enabled( $location ) ) {
1871
+ return;
1872
+ }
1873
+
1874
+ $values = cerber_antibot_gene();
1875
+
1876
+ if ( empty( $values ) || !is_array( $values ) ) {
1877
+ return;
1878
+ }
1879
+
1880
+ ?>
1881
+ <script type="text/javascript">
1882
+ jQuery(document).ready(function ($) {
1883
+ //$( document ).ajaxStart(function() {
1884
+ //});
1885
+
1886
+ <?php // Append form fields directly to the all forms ?>
1887
+
1888
+ for (var i = 0; i < document.forms.length; ++i) {
1889
+ var form = document.forms[i];
1890
+ <?php
1891
+ foreach ( $values[0] as $value ) {
1892
+ echo 'if ($(form).attr("method") != "get") { $(form).append(\'<input type="hidden" name="' . $value[0] . '" value="' . $value[1] . '" />\'); }'."\n";
1893
+ }
1894
+ ?>
1895
+ }
1896
+
1897
+ <?php // Ordinary submit ?>
1898
+
1899
+ $(document).on('submit', 'form', function () {
1900
+ <?php
1901
+ foreach ( $values[0] as $value ) {
1902
+ echo 'if ($(this).attr("method") != "get") { $(this).append(\'<input type="hidden" name="' . $value[0] . '" value="' . $value[1] . '" />\'); }'."\n";
1903
+ }
1904
+ ?>
1905
+ return true;
1906
+ });
1907
+
1908
+ <?php // Pure AJAX submit with two different types of form data (object and string) ?>
1909
+
1910
+ jQuery.ajaxSetup({
1911
+ beforeSend: function (e, data) {
1912
+
1913
+ //console.log(Object.getOwnPropertyNames(data).sort());
1914
+ //console.log(data.type);
1915
+
1916
+ if (data.type !== 'POST') return;
1917
+
1918
+ if (typeof data.data === 'object' && data.data !== null) {
1919
+ <?php
1920
+ foreach ( $values[0] as $value ) {
1921
+ echo 'data.data.append("' . $value[0] . '", "' . $value[1] . '");'."\n";
1922
+ }
1923
+ ?>
1924
+ }
1925
+ else {
1926
+ data.data = data.data + '<?php
1927
+ foreach ( $values[0] as $value ) {
1928
+ echo '&' . $value[0] . '=' . $value[1];
1929
+ }
1930
+ ?>';
1931
+ }
1932
+ }
1933
+ });
1934
+
1935
+ });
1936
+ </script>
1937
+ <?php
1938
+
1939
+ }
1940
+
1941
+ /**
1942
+ * Generates and saves antibot markers
1943
+ *
1944
+ * @return array|bool
1945
+ */
1946
+ function cerber_antibot_gene($recreate = false) {
1947
+
1948
+ if ( !crb_get_settings('botsany') && !crb_get_settings('botscomm') && !crb_get_settings('botsreg') ) {
1949
+ return false;
1950
+ }
1951
+
1952
+ $ret = array();
1953
+
1954
+ if (!$recreate) {
1955
+ $ret = cerber_get_site_option( 'cerber-antibot' );
1956
+ }
1957
+
1958
+ if ( $recreate || !$ret ) {
1959
+
1960
+ $ret = array();
1961
+
1962
+ $max = rand( 2, 4 );
1963
+ for ( $i = 1; $i <= $max; $i ++ ) {
1964
+ $length = rand( 6, 16 );
1965
+ $string1 = str_shuffle( 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-' );
1966
+ $string2 = str_shuffle( '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.@*_[]' );
1967
+ $ret[0][] = array( substr( $string1, 0, $length ), substr( $string2, 0, $length ) );
1968
+ }
1969
+
1970
+ $max = rand( 2, 4 );
1971
+ for ( $i = 1; $i <= $max; $i ++ ) {
1972
+ $length = rand( 6, 16 );
1973
+ $string1 = str_shuffle( 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-' );
1974
+ $string2 = str_shuffle( '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.@*_[]' );
1975
+ $ret[1][] = array( substr( $string1, 0, $length ), substr( $string2, 0, $length ) );
1976
+ }
1977
+
1978
+ update_site_option( 'cerber-antibot', $ret );
1979
+ }
1980
+
1981
+ return $ret;
1982
+ }
1983
+
1984
+ /**
1985
+ * Is a POST request (a form) submitted by a bot?
1986
+ *
1987
+ * @param $location string identificator of a place where we are check for a bot
1988
+ *
1989
+ * @return bool
1990
+ */
1991
+ function cerber_is_bot($location = '') {
1992
+ global $wp_cerber, $cerber_status;
1993
+ static $ret = null;
1994
+
1995
+ if ( isset( $ret ) ) {
1996
+ return $ret;
1997
+ }
1998
+
1999
+ if ( ! $location || ! cerber_is_http_post() || ( defined( 'DOING_CRON' ) && DOING_CRON ) ) {
2000
+ $ret = false;
2001
+
2002
+ return $ret;
2003
+ }
2004
+
2005
+ // Admin || AJAX requests by unauthorized users
2006
+ if ( is_admin() ) {
2007
+ if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
2008
+ if ( is_user_logged_in() ) {
2009
+ $ret = false;
2010
+ }
2011
+ elseif ( ! empty( $_POST['action'] ) ) {
2012
+ if ($_POST['action'] == 'heartbeat'){ // WP heartbeat
2013
+ $ret = false;
2014
+ }
2015
+ }
2016
+ elseif ( crb_get_settings( 'botssafe' ) ) {
2017
+ $ret = false;
2018
+ }
2019
+ }
2020
+ else {
2021
+ $ret = false;
2022
+ }
2023
+ }
2024
+
2025
+ if ($ret !== null) {
2026
+ return $ret;
2027
+ }
2028
+
2029
+ if ( ! cerber_antibot_enabled( $location ) ) {
2030
+ $ret = false;
2031
+
2032
+ return $ret;
2033
+ }
2034
+
2035
+ // Antibot whitelist
2036
+ if ( ( $list = crb_get_settings( 'botswhite' ) ) && is_array( $list ) ) {
2037
+ foreach ( $list as $exception ) {
2038
+ if ( false !== strpos( trim( $_SERVER['REQUEST_URI'], '/' ), $exception ) ) {
2039
+ $ret = false;
2040
+ return $ret;
2041
+ }
2042
+ }
2043
+ }
2044
+
2045
+ $antibot = cerber_antibot_gene();
2046
+
2047
+ $ret = false;
2048
+
2049
+ if ( ! empty( $antibot ) ) {
2050
+
2051
+ foreach ( $antibot[0] as $fields ) {
2052
+ if ( empty( $_POST[ $fields[0] ] ) || $_POST[ $fields[0] ] != $fields[1] ) {
2053
+ $ret = true;
2054
+ break;
2055
+ }
2056
+ }
2057
+
2058
+ if (!$ret){
2059
+ foreach ( $antibot[1] as $fields ) {
2060
+ if ( empty( $_COOKIE[ $fields[0] ] ) || $_COOKIE[ $fields[0] ] != $fields[1] ) {
2061
+ $ret = true;
2062
+ break;
2063
+ }
2064
+ }
2065
+ }
2066
+
2067
+ if ( $ret ) {
2068
+ $cerber_status = 11;
2069
+ lab_save_push( $wp_cerber->getRemoteIp(), 333, '' );
2070
+ }
2071
+ }
2072
+
2073
+ return $ret;
2074
+ }
2075
+
2076
+ function cerber_geo_allowed( $rule_id = '' ) {
2077
+
2078
+ if ( !$rule_id || ( defined( 'DOING_CRON' ) && DOING_CRON ) || !lab_lab() ) {
2079
+ return true;
2080
+ }
2081
+
2082
+ $tag = cerber_acl_check();
2083
+ if ( $tag == 'W' ) {
2084
+ return true;
2085
+ }
2086
+
2087
+ $rule = cerber_geo_rules( $rule_id );
2088
+ $wp_cerber = get_wp_cerber();
2089
+ if ( $rule && $country = lab_get_country( $wp_cerber->getRemoteIp(), false ) ) {
2090
+ if ( in_array( $country, $rule['list'] ) ) {
2091
+ if ( $rule['type'] == 'W' ) {
2092
+ return true;
2093
+ }
2094
+
2095
+ return false;
2096
+ }
2097
+ if ( $rule['type'] == 'W' ) {
2098
+ return false;
2099
+ }
2100
+
2101
+ return true;
2102
+ }
2103
+
2104
+ return true;
2105
+ }
2106
+
2107
+ /**
2108
+ * Retrieve and return GEO rule(s) from the DB
2109
+ *
2110
+ * @param string $rule_id Slug of a rule
2111
+ *
2112
+ * @return bool|array If a rule exists return array of countries
2113
+ */
2114
+ function cerber_geo_rules( $rule_id = '' ) {
2115
+ global $wpdb;
2116
+
2117
+ if (is_multisite()) {
2118
+ $geo = $wpdb->get_var( 'SELECT meta_value FROM ' . $wpdb->sitemeta . ' WHERE meta_key = "geo_rule_set"' );
2119
+ }
2120
+ else {
2121
+ $geo = $wpdb->get_var( 'SELECT option_value FROM ' . $wpdb->options . ' WHERE option_name = "geo_rule_set"' );
2122
+ }
2123
+
2124
+ if ( $geo ) {
2125
+ $rules = unserialize( $geo );
2126
+ if ( $rule_id ) {
2127
+ if ( ! empty( $rules[ $rule_id ] ) ) {
2128
+ $ret = $rules[ $rule_id ];
2129
+ }
2130
+ else {
2131
+ $ret = false;
2132
+ }
2133
+ }
2134
+ else {
2135
+ $ret = $rules;
2136
+ }
2137
+ }
2138
+ else {
2139
+ $ret = false;
2140
+ }
2141
+
2142
+ return $ret;
2143
+ }
2144
+
2145
+ /**
2146
+ * Set user session expiration
2147
+ *
2148
+ */
2149
+ add_filter( 'auth_cookie_expiration', function ( $expire ) {
2150
+ $time = crb_get_settings( 'auth_expire' );
2151
+ if ( $time ) {
2152
+ $expire = 60 * $time;
2153
+ }
2154
+
2155
+ return $expire;
2156
+ } );
2157
+
2158
+ // Track various activity -------------------------------------------------------------------------
2159
+
2160
+ add_action( 'wp_login', function ( $login, $user ) {
2161
+ global $wp_cerber_user_id;
2162
+ if ( ! empty( $_POST['log'] ) ) { // default WP form
2163
+ $user_login = htmlspecialchars( $_POST['log'] );
2164
+ }
2165
+ else {
2166
+ $user_login = $login;
2167
+ }
2168
+ $wp_cerber_user_id = $user->ID;
2169
+ cerber_log( 5, $user_login, $user->ID );
2170
+ }, 10, 2 );
2171
+
2172
+ /**
2173
+ * Catching some cases of authentication without using login form or not a default user login process
2174
+ */
2175
+ add_action( 'set_auth_cookie', function () {
2176
+ add_action( 'shutdown', function () { // deferred to allow the possible 'wp_login' action be logged first
2177
+ if ($user_id = get_current_user_id()) {
2178
+ cerber_log( 5, '', $user_id );
2179
+ }
2180
+ } );
2181
+ } );
2182
+
2183
+ /*add_action( 'wp_logout', function() {
2184
+ global $user_ID;
2185
+ if ( ! $user_ID ) {
2186
+ $user = wp_get_current_user();
2187
+ $user_ID = $user->ID;
2188
+ }
2189
+ cerber_log( 6, '', $user_ID );
2190
+ });*/
2191
+
2192
+ add_action( 'clear_auth_cookie', function () {
2193
+ $uid = get_current_user_id();
2194
+ if ( $uid ) {
2195
+ cerber_log( 6, '', $uid );
2196
+ }
2197
+ } );
2198
+
2199
+ //add_action( 'lostpassword_post', 'cerber_password_post' );
2200
+ add_action( 'retrieve_password', function ( $user_login ) {
2201
+ cerber_log( 21, $user_login );
2202
+ } );
2203
+
2204
+ add_action( 'password_reset', 'crb_pass_reset' );
2205
+ add_action( 'crb_after_reset', 'crb_pass_reset', 10, 2);
2206
+
2207
+ function crb_pass_reset( $user, $user_id = null) {
2208
+ if ( ! $user && $user_id ) {
2209
+ $user = get_user_by( 'id', $user_id );
2210
+ }
2211
+ if ( ! $user ) {
2212
+ return;
2213
+ }
2214
+ cerber_log( 20, $user->user_login, $user->ID );
2215
+ }
2216
+
2217
+ //add_action( 'register_new_user', function ( $user_id ) { // OLD
2218
+ // Fires in wp_insert_user()
2219
+ add_action( 'user_register', function ( $user_id ) { // @since 5.6
2220
+ $cid = get_current_user_id();
2221
+ if ($user = get_user_by( 'ID', $user_id )) {
2222
+ if ( $cid && $cid != $user_id ) {
2223
+ $ac = 1;
2224
+ }
2225
+ else {
2226
+ $ac = 2;
2227
+ }
2228
+ cerber_log( $ac, $user->user_login, $user_id );
2229
+ crb_log_user_ip( $user_id, $cid );
2230
+ }
2231
+ });
2232
+
2233
+ // Fires after a new user has been created in WP dashboard.
2234
+ add_action( 'edit_user_created_user', function ( $user_id, $notify = null ) {
2235
+ if ( $user_id && $user = get_user_by( 'ID', $user_id ) ) {
2236
+ cerber_log( 1, $user->user_login, $user_id );
2237
+ crb_log_user_ip( $user_id );
2238
+ }
2239
+ }, 10, 2 );
2240
+
2241
+ // Log IP address of user registration independently
2242
+ function crb_log_user_ip( $user_id, $by_user = null ) {
2243
+ global $wp_cerber;
2244
+ if ( ! $user_id ) {
2245
+ return;
2246
+ }
2247
+ if ( ! $by_user ) {
2248
+ $by_user = get_current_user_id();
2249
+ }
2250
+ add_user_meta( $user_id, '_crb_reg_', array( 'IP' => $wp_cerber->getRemoteIp(), 'user' => $by_user ) );
2251
+ }
2252
+
2253
+ // Lockouts routines ---------------------------------------------------------------------
2254
+
2255
+ /**
2256
+ * Lock out IP address if it is an alien IP only (browser does not have valid Cerber groove)
2257
+ *
2258
+ * @param $ip string IP address to block
2259
+ * @param integer $reason_id ID of reason of blocking
2260
+ * @param string $details Reason of blocking
2261
+ * @param null $duration Duration of blocking
2262
+ *
2263
+ * @return bool|false|int
2264
+ */
2265
+ function cerber_soft_block_add( $ip, $reason_id, $details = '', $duration = null ) {
2266
+ if ( cerber_check_groove() ) {
2267
+ return false;
2268
+ }
2269
+
2270
+ return cerber_block_add( $ip, $reason_id, $details, $duration );
2271
+ }
2272
+
2273
+ /**
2274
+ * Lock out IP address
2275
+ *
2276
+ * @param $ip string IP address to block
2277
+ * @param integer $reason_id ID of reason of blocking
2278
+ * @param string $details Reason of blocking
2279
+ * @param int $duration Duration of blocking
2280
+ *
2281
+ * @return bool|false|int
2282
+ */
2283
+ function cerber_block_add( $ip = '', $reason_id = 1, $details = '', $duration = null ) {
2284
+ global $wpdb;
2285
+
2286
+ $wp_cerber = get_wp_cerber();
2287
+
2288
+ //$wp_cerber->setProcessed();
2289
+
2290
+ if ( empty($ip) ) {
2291
+ $ip = $wp_cerber->getRemoteIp();
2292
+ }
2293
+
2294
+ if ( cerber_get_block( $ip ) ) {
2295
+ return false;
2296
+ }
2297
+
2298
+ if ( cerber_acl_check( $ip ) ) {
2299
+ return false;
2300
+ }
2301
+
2302
+ $ip_address = $ip;
2303
+
2304
+ lab_save_push( $ip, $reason_id, $details );
2305
+
2306
+ if ( $wp_cerber->getSettings( 'subnet' ) ) {
2307
+ $ip = cerber_get_subnet( $ip );
2308
+ $activity = 11;
2309
+ }
2310
+ else {
2311
+ $activity = 10;
2312
+ }
2313
+
2314
+ /*if ( $wpdb->get_var( $wpdb->prepare( 'SELECT count(ip) FROM ' . CERBER_BLOCKS_TABLE . ' WHERE ip = %s', $ip ) ) ) {
2315
+ return false;
2316
+ }*/
2317
+
2318
+ $reason = cerber_get_reason( $reason_id );
2319
+ if ( $details ) {
2320
+ $reason .= ': <b>' . $details . '</b>';
2321
+ }
2322
+
2323
+ if ( ! $duration ) {
2324
+ $duration = cerber_calc_duration( $ip );
2325
+ }
2326
+ $until = time() + $duration;
2327
+
2328
+ //$result = $wpdb->query($wpdb->prepare('INSERT INTO '. CERBER_BLOCKS_TABLE . ' (ip,block_until,reason) VALUES (%s,%d,%s)',$ip,$until,$reason));
2329
+ $result = $wpdb->insert( CERBER_BLOCKS_TABLE, array(
2330
+ 'ip' => $ip,
2331
+ 'block_until' => $until,
2332
+ 'reason' => $reason
2333
+ ), array( '%s', '%d', '%s' ) );
2334
+
2335
+ if ( $result ) {
2336
+ cerber_log( $activity, null, null, $ip_address );
2337
+ $wp_cerber->setLocked();
2338
+ do_action( 'cerber_ip_locked', array( 'IP' => $ip_address, 'reason' => $reason ) );
2339
+ $result = true;
2340
+ }
2341
+ else {
2342
+ cerber_db_error_log();
2343
+ $result = false;
2344
+ }
2345
+
2346
+ if ( $wp_cerber->getSettings( 'notify' ) ) {
2347
+ //$count = $wpdb->get_var( 'SELECT count(ip) FROM ' . CERBER_BLOCKS_TABLE );
2348
+ $count = cerber_blocked_num();
2349
+ if ( $count > $wp_cerber->getSettings( 'above' ) ) {
2350
+ cerber_send_notify( 'lockout', '', $ip_address );
2351
+ }
2352
+ }
2353
+
2354
+ return $result;
2355
+ }
2356
+
2357
+ function cerber_block_delete( $ip ) {
2358
+ global $wpdb;
2359
+
2360
+ return $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . CERBER_BLOCKS_TABLE . ' WHERE ip = %s', $ip ) );
2361
+ }
2362
+
2363
+
2364
+ /**
2365
+ *
2366
+ * Check if an IP address is currently blocked. With C subnet also.
2367
+ *
2368
+ * @param string $ip an IP address
2369
+ *
2370
+ * @return bool true if IP is locked out
2371
+ */
2372
+ function cerber_block_check( $ip = '' ) {
2373
+
2374
+ // @since 4.8
2375
+ if (cerber_get_block($ip)) return true;
2376
+
2377
+ return false;
2378
+ }
2379
+
2380
+ /**
2381
+ *
2382
+ * Return the lockout row for an IP if it is blocked. With C subnet also.
2383
+ *
2384
+ * @param string $ip an IP address
2385
+ *
2386
+ * @return object|bool object if IP is locked out, false otherwise
2387
+ */
2388
+ function cerber_get_block( $ip = '' ) {
2389
+ global $wpdb, $wp_cerber;
2390
+
2391
+ if ( ! $ip ) {
2392
+ $wp_cerber = get_wp_cerber();
2393
+ $ip = $wp_cerber->getRemoteIp();
2394
+ }
2395
+
2396
+ if ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
2397
+ return false;
2398
+ }
2399
+
2400
+ $where = ' WHERE ip = "' . $ip . '"';
2401
+ if ( cerber_is_ipv4( $ip ) ) {
2402
+ $subnet = cerber_get_subnet( $ip );
2403
+ $where .= ' OR ip = "' . $subnet . '"';
2404
+ }
2405
+ if ( $ret = $wpdb->get_row( 'SELECT * FROM ' . CERBER_BLOCKS_TABLE . $where ) ) {
2406
+ return $ret;
2407
+ }
2408
+
2409
+ return false;
2410
+ }
2411
+
2412
+ /**
2413
+ * Return the number of currently locked out IPs
2414
+ *
2415
+ * @return int the number of currently locked out IPs
2416
+ * @since 3.0
2417
+ */
2418
+ function cerber_blocked_num() {
2419
+ global $wpdb;
2420
+ $count = $wpdb->get_var( 'SELECT count(ip) FROM ' . CERBER_BLOCKS_TABLE );
2421
+
2422
+ return absint( $count );
2423
+ }
2424
+
2425
+ /**
2426
+ * Calculate duration for a lockout of an IP address based on settings
2427
+ *
2428
+ * @param string $ip
2429
+ *
2430
+ * @return integer Duration in seconds
2431
+ */
2432
+ function cerber_calc_duration( $ip ) {
2433
+ global $wpdb;
2434
+ $range = time() - crb_get_settings( 'aglast' ) * 3600;
2435
+ //$lockouts = $wpdb->get_var( $wpdb->prepare( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE ip = %s AND activity IN (10,11) AND stamp > %d', $ip, $range ) );
2436
+ $lockouts = $wpdb->get_var( 'SELECT COUNT(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE ip = "' . $ip . '" AND activity IN (10,11) AND stamp > ' . $range );
2437
+ if ( $lockouts >= crb_get_settings( 'aglocks' ) ) {
2438
+ $ret = crb_get_settings( 'agperiod' ) * 3600;
2439
+ }
2440
+ else {
2441
+ $ret = crb_get_settings( 'lockout' ) * 60;
2442
+ }
2443
+ $ret = absint( $ret );
2444
+ if ( $ret < 60 ) {
2445
+ $ret = 60;
2446
+ }
2447
+
2448
+ return $ret;
2449
+ }
2450
+
2451
+ /**
2452
+ * Calculation of remaining attempts
2453
+ *
2454
+ * @param $ip string an IP address
2455
+ * @param $check_acl bool if true will check the White IP ACL first
2456
+ * @param $activity string comma-separated list of activity IDs to calculate for
2457
+ * @param $allowed int Allowed attempts within $period
2458
+ * @param $period int Period for count attempts
2459
+ *
2460
+ * @return int Allowed attempts for now
2461
+ */
2462
+ function cerber_get_remain_count( $ip = '', $check_acl = true, $activity = '7,51,52', $allowed = null, $period = null ) {
2463
+ global $wpdb, $wp_cerber;
2464
+ if ( ! $ip ) {
2465
+ $ip = $wp_cerber->getRemoteIp();
2466
+ }
2467
+
2468
+ if ( ! $allowed ) {
2469
+ $allowed = absint( crb_get_settings( 'attempts' ) );
2470
+ }
2471
+
2472
+ if ( $check_acl && cerber_acl_check( $ip, 'W' ) ) {
2473
+ return $allowed; // whitelist = infinity attempts
2474
+ }
2475
+
2476
+ if ( ! $period ) {
2477
+ $period = absint( crb_get_settings( 'period' ) );
2478
+ }
2479
+
2480
+ $range = time() - $period * 60;
2481
+ // TODO: remove prepare, replace $activity with an array of integer
2482
+ $attempts = $wpdb->get_var( $wpdb->prepare( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE ip = %s AND activity IN (%s) AND stamp > %d', $ip, $activity, $range ) );
2483
+
2484
+ if ( ! $attempts ) {
2485
+ return $allowed;
2486
+ }
2487
+ else {
2488
+ $ret = $allowed - $attempts;
2489
+ }
2490
+ $ret = $ret < 0 ? 0 : $ret;
2491
+
2492
+ return $ret;
2493
+ }
2494
+
2495
+ /**
2496
+ * Is a given IP is allowed to do restricted things?
2497
+ * Here Cerber makes its decision.
2498
+ *
2499
+ * @param $ip string IP address
2500
+ *
2501
+ * @return bool
2502
+ */
2503
+ function cerber_is_allowed( $ip = '' ) {
2504
+
2505
+ if ( ! $ip ) {
2506
+ $wp_cerber = get_wp_cerber();
2507
+ $ip = $wp_cerber->getRemoteIp();
2508
+ }
2509
+
2510
+ if ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
2511
+ return false;
2512
+ }
2513
+
2514
+ // @since 4.7.9
2515
+ if ( cerber_block_check( $ip ) ) {
2516
+ return false;
2517
+ }
2518
+
2519
+ $tag = cerber_acl_check( $ip );
2520
+ if ( $tag == 'W' ) {
2521
+ return true;
2522
+ }
2523
+ if ( $tag == 'B' ) {
2524
+ return false;
2525
+ }
2526
+
2527
+ /* @since 4.7.9
2528
+ if ( cerber_block_check( $ip ) ) {
2529
+ return false;
2530
+ }*/
2531
+
2532
+ if ( cerber_is_citadel() ) {
2533
+ return false;
2534
+ }
2535
+
2536
+ if ( lab_is_blocked( $ip, false ) ) {
2537
+ return false;
2538
+ }
2539
+
2540
+ return true;
2541
+ }
2542
+
2543
+ /**
2544
+ * Check if a given username is not permitted to login or register
2545
+ *
2546
+ * @param $username string
2547
+ *
2548
+ * @return bool true if username is prohibited
2549
+ */
2550
+ function cerber_is_prohibited( $username ) {
2551
+ if ( $list = (array) crb_get_settings( 'prohibited' ) ) {
2552
+ foreach ( $list as $item ) {
2553
+ if ( mb_substr( $item, 0, 1 ) == '/' && mb_substr( $item, - 1 ) == '/' ) {
2554
+ $pattern = trim( $item, '/' );
2555
+ if ( mb_ereg_match( $pattern, $username, 'i' ) ) {
2556
+ return true;
2557
+ }
2558
+ }
2559
+ elseif ($username === $item){
2560
+ return true;
2561
+ }
2562
+ }
2563
+ }
2564
+
2565
+ return false;
2566
+ }
2567
+
2568
+ // TODO: Merge with $wp_cerber->getStatus();
2569
+ function cerber_get_status( $ip ) {
2570
+ global $cerber_status;
2571
+
2572
+ if ( ! empty( $cerber_status ) ) {
2573
+ return absint($cerber_status);
2574
+ }
2575
+
2576
+ if ( cerber_block_check( $ip ) ) {
2577
+ return 13;
2578
+ }
2579
+
2580
+ $tag = cerber_acl_check( $ip );
2581
+ if ( $tag == 'W' ) {
2582
+ return 0;
2583
+ }
2584
+ if ( $tag == 'B' ) {
2585
+ return 14;
2586
+ }
2587
+
2588
+ if ( cerber_is_citadel() ) {
2589
+ return 12;
2590
+ }
2591
+
2592
+ if ( lab_is_blocked( $ip, false ) ) {
2593
+ return 15;
2594
+ }
2595
+
2596
+
2597
+ return 0;
2598
+ }
2599
+
2600
+ // Access lists (ACL) routines --------------------------------------------------------------------------------
2601
+
2602
+ // TODO: move to dashboard.php
2603
+ /**
2604
+ * Add IP to specified access list
2605
+ *
2606
+ * @param $ip string|array single IP address, string with IP network, range or associative range array
2607
+ * @param $tag string 'B'|'W'
2608
+ *
2609
+ * @return bool|int|object Result of operation
2610
+ */
2611
+ function cerber_acl_add( $ip, $tag, $comment = '') {
2612
+ global $wpdb;
2613
+ if ( is_string( $ip ) ) {
2614
+ if ( ! cerber_is_ipv4( $ip ) ) {
2615
+ $ip = cerber_short_ipv6( $ip );
2616
+ }
2617
+ if ( $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(ip) FROM ' . CERBER_ACL_TABLE . ' WHERE ip = %s', $ip ) ) ) {
2618
+ return false; //__( 'Element is already in list', 'wp-cerber' );
2619
+ }
2620
+ $range = cerber_any2range( $ip );
2621
+ if ( is_array( $range ) ) {
2622
+ $begin = $range['begin'];
2623
+ $end = $range['end'];
2624
+ }
2625
+ else {
2626
+ if (cerber_is_ipv4($ip)) {
2627
+ $begin = ip2long( $ip );
2628
+ $end = ip2long( $ip );
2629
+ }
2630
+ else{
2631
+ $begin = 0;
2632
+ $end = 0;
2633
+ }
2634
+ }
2635
+
2636
+ $result = $wpdb->insert( CERBER_ACL_TABLE, array( 'ip' => $ip,
2637
+ 'ip_long_begin' => $begin,
2638
+ 'ip_long_end' => $end,
2639
+ 'tag' => $tag,
2640
+ 'comments' => $comment
2641
+ ), array( '%s', '%d', '%d', '%s', '%s' ) );
2642
+ return $result;
2643
+ }
2644
+ elseif ( is_array( $ip ) ) {
2645
+ $range = $ip['range'];
2646
+ $begin = $ip['begin'];
2647
+ $end = $ip['end'];
2648
+ if ( $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(ip) FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin = %d AND ip_long_end = %d', $begin, $end ) ) ) {
2649
+ return false;
2650
+ }
2651
+
2652
+ $result = $wpdb->insert( CERBER_ACL_TABLE, array( 'ip' => $range,
2653
+ 'ip_long_begin' => $begin,
2654
+ 'ip_long_end' => $end,
2655
+ 'tag' => $tag,
2656
+ 'comments' => $comment
2657
+ ), array( '%s', '%d', '%d', '%s', '%s' ) );
2658
+
2659
+ return $result;
2660
+
2661
+ //return $wpdb->query( $wpdb->prepare( 'INSERT INTO ' . CERBER_ACL_TABLE . ' (ip, ip_long_begin, ip_long_end, tag) VALUES (%s,%d,%d,%s)', $range, $begin, $end, $tag ) );
2662
+ }
2663
+
2664
+ return false;
2665
+ }
2666
+ // TODO: move to dashboard.php
2667
+ function cerber_add_white( $ip, $comment = '' ) {
2668
+ return cerber_acl_add( $ip, 'W', $comment );
2669
+ }
2670
+ // TODO: move to dashboard.php
2671
+ function cerber_add_black( $ip, $comment = '') {
2672
+ return cerber_acl_add( $ip, 'B', $comment );
2673
+ }
2674
+ // TODO: move to dashboard.php
2675
+ function cerber_acl_remove( $ip ) {
2676
+ global $wpdb;
2677
+ if ( is_string( $ip ) ) {
2678
+ return $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . CERBER_ACL_TABLE . ' WHERE ip = %s ', $ip ) );
2679
+ } elseif ( is_array( $ip ) ) {
2680
+ return $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin = %d AND ip_long_end = %d', $ip['begin'], $ip['end'] ) );
2681
+ }
2682
+
2683
+ return false;
2684
+ }
2685
+
2686
+ // TODO: move to dashboard.php
2687
+ /**
2688
+ * Can a given IP (user input) be added to the blacklist
2689
+ *
2690
+ * @param $ip
2691
+ * @param string $list
2692
+ *
2693
+ * @return bool
2694
+ */
2695
+ function cerber_can_be_listed( $ip, $list = 'B' ) {
2696
+ global $wp_cerber;
2697
+ if ( $list == 'B' ) {
2698
+ if ( crb_acl_is_white( $wp_cerber->getRemoteIp() ) ) {
2699
+ return true;
2700
+ }
2701
+ if ( filter_var( $ip, FILTER_VALIDATE_IP ) ) {
2702
+ if ( cerber_is_myip( $ip ) ) {
2703
+ return false;
2704
+ }
2705
+ }
2706
+ $range = cerber_any2range( $ip );
2707
+ if ( cerber_is_ip_in_range( $range ) ) {
2708
+ return false;
2709
+ }
2710
+
2711
+ return true;
2712
+ }
2713
+
2714
+ return true;
2715
+ }
2716
+
2717
+ /**
2718
+ * Check ACLs for given IP. Some extra lines for performance reason.
2719
+ *
2720
+ * @param string $ip
2721
+ * @param string $tag
2722
+ *
2723
+ * @return bool|string
2724
+ */
2725
+ function cerber_acl_check( $ip = null, $tag = '' ) {
2726
+ global $wpdb, $wp_cerber;
2727
+ static $cache; // @since 5.26
2728
+
2729
+ if ( ! $ip ) {
2730
+ $wp_cerber = get_wp_cerber();
2731
+ $ip = $wp_cerber->getRemoteIp();
2732
+ //$ip = cerber_get_remote_ip();
2733
+ }
2734
+
2735
+ $key = cerber_get_id_ip( $ip ) . (string)$tag;
2736
+
2737
+ if ( isset( $cache[ $key ] ) ) {
2738
+ return $cache[ $key ];
2739
+ }
2740
+
2741
+ if ( ! cerber_is_ipv4( $ip ) ) {
2742
+ $ret = cerber_acl_checkV6( $ip, $tag );
2743
+ $cache[ $key ] = $ret;
2744
+ return $ret;
2745
+ }
2746
+
2747
+ $long = ip2long( $ip );
2748
+
2749
+ if ( $tag ) {
2750
+ if ( $tag != 'W' && $tag != 'B' ) {
2751
+ $ret = false;
2752
+ }
2753
+ elseif ( $wpdb->get_var( 'SELECT ip FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin <= '.$long.' AND '.$long.' <= ip_long_end AND tag = "'.$tag.'" LIMIT 1' ) ) {
2754
+ $ret = true;
2755
+ }
2756
+ else {
2757
+ $ret = false;
2758
+ }
2759
+
2760
+ $cache[ $key ] = $ret;
2761
+ return $ret;
2762
+ }
2763
+ else {
2764
+ // We use two queries because of possible overlapping an IP and its network
2765
+ if ( $ret = $wpdb->get_var( 'SELECT tag FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin <= ' . $long . ' AND ' . $long . ' <= ip_long_end AND tag = "W" LIMIT 1' ) ) {
2766
+ $cache[ $key ] = $ret;
2767
+ return $ret;
2768
+ }
2769
+ if ( $ret = $wpdb->get_var( 'SELECT tag FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin <= ' . $long . ' AND ' . $long . ' <= ip_long_end AND tag = "B" LIMIT 1' ) ) {
2770
+ $cache[ $key ] = $ret;
2771
+ return $ret;
2772
+ }
2773
+
2774
+ $cache[ $key ] = false;
2775
+ return false;
2776
+ }
2777
+ }
2778
+
2779
+ /**
2780
+ * IPv6 version of cerber_acl_check() without subnets and ranges
2781
+ *
2782
+ * @param null $ip
2783
+ * @param string $tag
2784
+ *
2785
+ * @return bool|null|string
2786
+ */
2787
+ function cerber_acl_checkV6( $ip = null, $tag = '' ) {
2788
+ global $wpdb, $wp_cerber;
2789
+ if ( ! $ip ) {
2790
+ $ip = $wp_cerber->getRemoteIp();
2791
+ }
2792
+ if ( $tag ) {
2793
+ if ( $wpdb->get_var( $wpdb->prepare( 'SELECT count(ip) FROM ' . CERBER_ACL_TABLE . ' WHERE ip = %s AND tag = %s', $ip, $tag ) ) ) {
2794
+ return true;
2795
+ }
2796
+
2797
+ return false;
2798
+ } else {
2799
+ if ( $ret = $wpdb->get_var( $wpdb->prepare( 'SELECT tag FROM ' . CERBER_ACL_TABLE . ' WHERE ip = %s', $ip ) ) ) {
2800
+ return $ret;
2801
+ }
2802
+
2803
+ return false;
2804
+ }
2805
+ }
2806
+
2807
+
2808
+ function crb_acl_is_white( $ip = null ){
2809
+
2810
+ $acl = cerber_acl_check( $ip );
2811
+ if ( $acl == 'W' ) {
2812
+ return true;
2813
+ }
2814
+
2815
+ return false;
2816
+ }
2817
+
2818
+ /*
2819
+ * Logging directly to the file
2820
+ *
2821
+ * CERBER_FAIL_LOG optional, full path including filename to the log file
2822
+ * CERBER_LOG_FACILITY optional, use to specify what type of program is logging the messages
2823
+ *
2824
+ * */
2825
+ function cerber_file_log( $user_login, $ip ) {
2826
+ if ( defined( 'CERBER_FAIL_LOG' ) ) {
2827
+ if ( $log = @fopen( CERBER_FAIL_LOG, 'a' ) ) {
2828
+ $pid = absint( @posix_getpid() );
2829
+ @fwrite( $log, date( 'M j H:i:s ' ) . $_SERVER['SERVER_NAME'] . ' Cerber(' . $_SERVER['HTTP_HOST'] . ')[' . $pid . ']: Authentication failure for ' . $user_login . ' from ' . $ip . "\n" );
2830
+ @fclose( $log );
2831
+ }
2832
+ } else {
2833
+ @openlog( 'Cerber(' . $_SERVER['HTTP_HOST'] . ')', LOG_NDELAY | LOG_PID, defined( 'CERBER_LOG_FACILITY' ) ? CERBER_LOG_FACILITY : LOG_AUTH );
2834
+ @syslog( LOG_NOTICE, 'Authentication failure for ' . $user_login . ' from ' . $ip );
2835
+ @closelog();
2836
+ }
2837
+ }
2838
+
2839
+ /*
2840
+ Return wildcard - string like subnet Class C
2841
+ */
2842
+ function cerber_get_subnet( $ip ) {
2843
+ return preg_replace( '/\.\d{1,3}$/', '.*', $ip );
2844
+ }
2845
+
2846
+ /*
2847
+ Check if given IP address or wildcard or CIDR is valid
2848
+ */
2849
+ function cerber_is_ip_or_net( $ip ) {
2850
+ if ( filter_var( $ip, FILTER_VALIDATE_IP ) ) {
2851
+ return true;
2852
+ }
2853
+ // WILDCARD: 192.168.1.*
2854
+ $ip = str_replace( '*', '0', $ip );
2855
+ //if ( @inet_pton( $ip ) ) {
2856
+ if ( filter_var( $ip, FILTER_VALIDATE_IP ) ) {
2857
+ return true;
2858
+ }
2859
+ // CIDR: 192.168.1/24
2860
+ if ( strpos( $ip, '/' ) ) {
2861
+ $cidr = explode( '/', $ip );
2862
+ $net = $cidr[0];
2863
+ $mask = absint( $cidr[1] );
2864
+ $dots = substr_count( $net, '.' );
2865
+ if ( $dots < 3 ) {
2866
+ if ( $dots == 1 ) {
2867
+ $net .= '.0.0';
2868
+ } elseif ( $dots == 2 ) {
2869
+ $net .= '.0';
2870
+ }
2871
+ }
2872
+ if ( ! cerber_is_ipv4( $net ) ) {
2873
+ return false;
2874
+ }
2875
+ if ( ! is_numeric( $mask ) ) {
2876
+ return false;
2877
+ }
2878
+
2879
+ return true;
2880
+ }
2881
+
2882
+ return false;
2883
+ }
2884
+
2885
+ /**
2886
+ * Tries to recognize single IP address or IP v4 range (with dash) in a given string.
2887
+ *
2888
+ * @param string $string String to recognize IP address in
2889
+ *
2890
+ * @return array|bool|string Return single IP address or wildcard or CIDR as a string, and IP range as an array.
2891
+ */
2892
+ function cerber_parse_ip( $string = '' ) {
2893
+ $string = trim( $string );
2894
+ if ( cerber_is_ip_or_net( $string ) ) {
2895
+ return $string;
2896
+ }
2897
+ $explode = explode( '-', $string );
2898
+ if ( ! is_array( $explode ) || ! $explode ) {
2899
+ return false;
2900
+ }
2901
+ $range = array();
2902
+ $count = 0;
2903
+ foreach ( $explode as $ip ) {
2904
+ $ip = trim( $ip );
2905
+ if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) ) {
2906
+ $range[] = $ip;
2907
+ $count ++;
2908
+ if ( $count >= 2 ) {
2909
+ break;
2910
+ }
2911
+ }
2912
+ }
2913
+ if ( count( $range ) < 2 ) {
2914
+ return false;
2915
+ }
2916
+ if ( ip2long( $range[1] ) <= ip2long( $range[0] ) ) {
2917
+ return false;
2918
+ }
2919
+
2920
+ return array(
2921
+ 'range' => $range[0] . ' - ' . $range[1],
2922
+ 'begin_ip' => $range[0],
2923
+ 'end_ip' => $range[1],
2924
+ 'begin' => ip2long( $range[0] ),
2925
+ 'end' => ip2long( $range[1] ),
2926
+ );
2927
+ }
2928
+
2929
+ /**
2930
+ * Convert a network wildcard string like x.x.x.* to an IP v4 range
2931
+ *
2932
+ * @param $wildcard string
2933
+ *
2934
+ * @return array|bool|string False if no wildcard found, otherwise result of cerber_parse_ip()
2935
+ */
2936
+ function cerber_wildcard2range( $wildcard = '' ) {
2937
+ $begin = str_replace( '*', '0', $wildcard );
2938
+ $end = str_replace( '*', '255', $wildcard );
2939
+ if ( ! cerber_is_ipv4( $begin ) ) {
2940
+ return false;
2941
+ }
2942
+ if ( ! cerber_is_ipv4( $end ) ) {
2943
+ return false;
2944
+ }
2945
+
2946
+ return cerber_parse_ip( $begin . ' - ' . $end );
2947
+ }
2948
+
2949
+ /**
2950
+ * Convert a CIDR to an IP v4 range
2951
+ *
2952
+ * @param $cidr string
2953
+ *
2954
+ * @return array|bool|string
2955
+ */
2956
+ function cerber_cidr2range( $cidr = '' ) {
2957
+ if ( ! strpos( $cidr, '/' ) ) {
2958
+ return false;
2959
+ }
2960
+ $cidr = explode( '/', $cidr );
2961
+ $net = $cidr[0];
2962
+ $mask = absint( $cidr[1] );
2963
+ $dots = substr_count( $net, '.' );
2964
+ if ( $dots < 3 ) { // not completed CIDR
2965
+ if ( $dots == 1 ) {
2966
+ $net .= '.0.0';
2967
+ } elseif ( $dots == 2 ) {
2968
+ $net .= '.0';
2969
+ }
2970
+ }
2971
+ if ( ! cerber_is_ipv4( $net ) ) {
2972
+ return false;
2973
+ }
2974
+ if ( ! is_numeric( $mask ) ) {
2975
+ return false;
2976
+ }
2977
+ $begin = long2ip( ( ip2long( $net ) ) & ( ( - 1 << ( 32 - (int) $mask ) ) ) );
2978
+ $end = long2ip( ( ip2long( $net ) ) + pow( 2, ( 32 - (int) $mask ) ) - 1 );
2979
+
2980
+ return cerber_parse_ip( $begin . ' - ' . $end );
2981
+ }
2982
+
2983
+ /**
2984
+ * Try to recognize an IP range or a single IP in a string.
2985
+ *
2986
+ * @param $string string Network wildcard, CIDR or IP range.
2987
+ *
2988
+ * @return array|bool|string
2989
+ */
2990
+ function cerber_any2range( $string = '' ) {
2991
+ // Do not change the order!
2992
+ $ret = cerber_wildcard2range( $string );
2993
+ if ( ! $ret ) {
2994
+ $ret = cerber_cidr2range( $string );
2995
+ }
2996
+ if ( ! $ret ) {
2997
+ $ret = cerber_parse_ip( $string ); // must be last due to checking for cidr and wildcard
2998
+ }
2999
+
3000
+ return $ret;
3001
+ }
3002
+
3003
+ /*
3004
+ Check for given IP address or subnet belong to this session.
3005
+ */
3006
+ function cerber_is_myip( $ip ) {
3007
+ global $wp_cerber;
3008
+ if ( ! is_string( $ip ) ) {
3009
+ return false;
3010
+ }
3011
+ $remote_ip = $wp_cerber->getRemoteIp();
3012
+ if ( $ip == $remote_ip ) {
3013
+ return true;
3014
+ }
3015
+ if ( $ip == cerber_get_subnet( $remote_ip ) ) {
3016
+ return true;
3017
+ }
3018
+
3019
+ return false;
3020
+ }
3021
+
3022
+ function cerber_is_ip_in_range( $range, $ip = null ) {
3023
+ global $wp_cerber;
3024
+ if ( ! is_array( $range ) ) {
3025
+ return false;
3026
+ }
3027
+ if ( ! $ip ) {
3028
+ $ip = $wp_cerber->getRemoteIp();
3029
+ }
3030
+ $long = ip2long( $ip );
3031
+ if ( $range['begin'] <= $long && $long <= $range['end'] ) {
3032
+ return true;
3033
+ }
3034
+
3035
+ return false;
3036
+ }
3037
+
3038
+ /**
3039
+ * Display 404 page to bump bots and bad guys
3040
+ *
3041
+ * @param bool $simple If true force displaying basic 404 page
3042
+ */
3043
+ function cerber_404_page($simple = false) {
3044
+ global $wp_query;
3045
+
3046
+ if ( !$simple ) {
3047
+ if ( function_exists( 'status_header' ) ) {
3048
+ status_header( '404' );
3049
+ }
3050
+ if ( isset( $wp_query ) && is_object( $wp_query ) ) {
3051
+ $wp_query->set_404();
3052
+ }
3053
+ if ( 0 == crb_get_settings( 'page404' ) ) {
3054
+ $template = null;
3055
+ if ( function_exists( 'get_404_template' ) ) {
3056
+ $template = get_404_template();
3057
+ }
3058
+ if ( function_exists( 'apply_filters' ) ) {
3059
+ $template = apply_filters( 'cerber_404_template', $template );
3060
+ }
3061
+ if ( $template && @file_exists( $template ) ) {
3062
+ include( $template );
3063
+ exit;
3064
+ }
3065
+ }
3066
+ }
3067
+
3068
+ header( 'HTTP/1.0 404 Not Found', true, 404 );
3069
+ echo '<html><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL ' . esc_url( $_SERVER['REQUEST_URI'] ) . ' was not found on this server.</p></body></html>';
3070
+ cerber_traffic_log(); // do not remove!
3071
+ exit;
3072
+ }
3073
+ /*
3074
+ Display Forbidden page
3075
+ */
3076
+ function cerber_forbidden_page() {
3077
+ status_header( '403' );
3078
+ header( 'HTTP/1.0 403 Access Forbidden', true, 403 );
3079
+ ?>
3080
+ <!DOCTYPE html>
3081
+ <html style="height: 100%;">
3082
+ <meta charset="UTF-8">
3083
+ <head><title>403 Access Forbidden</title></head>
3084
+ <body style="height: 100%;">
3085
+ <div style="display: flex; align-items: center; justify-content: center; height: 70%;">
3086
+ <div style="background-color: #eee; width: 70%; border: solid 3px #ddd; padding: 1.5em 3em 3em 3em; font-family: Arial, Helvetica, sans-serif;">
3087
+ <div style="display: table-row;">
3088
+ <div style="display: table-cell; font-size: 150px; color: red; vertical-align: middle; padding-right: 50px;">
3089
+ &#9995;
3090
+ </div>
3091
+ <div style="display: table-cell; vertical-align: middle;">
3092
+ <h1><?php _e("We're sorry, you are not allowed to proceed", 'wp-cerber'); ?></h1>
3093
+ <p>Our server stopped processing your request. Your request looks suspicious or similar to automated
3094
+ requests from spam posting software.</p>
3095
+ <p>If you believe you should be able to perform this request, please let us know.</p>
3096
+ </div>
3097
+ </div>
3098
+ </div>
3099
+ </div>
3100
+ </body>
3101
+ </html>
3102
+ <?php
3103
+ cerber_traffic_log(); // do not remove!
3104
+ exit;
3105
+ }
3106
+
3107
+ // Citadel mode -------------------------------------------------------------------------------------
3108
+
3109
+ function cerber_enable_citadel() {
3110
+ global $wp_cerber;
3111
+ if ( get_transient( 'cerber_citadel' ) ) {
3112
+ return;
3113
+ }
3114
+ set_transient( 'cerber_citadel', true, crb_get_settings( 'ciduration' ) * 60 );
3115
+ cerber_log( 12 );
3116
+
3117
+ // Notify admin
3118
+ if ( $wp_cerber->getSettings( 'cinotify' ) ) {
3119
+ cerber_send_notify( 'citadel' );
3120
+ }
3121
+ }
3122
+
3123
+ function cerber_disable_citadel() {
3124
+ delete_transient( 'cerber_citadel' );
3125
+ }
3126
+
3127
+ function cerber_is_citadel() {
3128
+ if ( get_transient( 'cerber_citadel' ) ) {
3129
+ return true;
3130
+ }
3131
+
3132
+ return false;
3133
+ }
3134
+
3135
+ // Hardening -------------------------------------------------------------------------------------
3136
+
3137
+ //if (!cerber_acl_check(cerber_get_ip(),'W') && false) {
3138
+
3139
+ /*
3140
+ if ($hardening['ping']) {
3141
+ add_filter( 'xmlrpc_methods', 'remove_xmlrpc_pingback' );
3142
+ function remove_xmlrpc_pingback( $methods ) {
3143
+ unset($methods['pingback.ping']);
3144
+ unset($methods['pingback.extensions.getPingbacks']);
3145
+ return $methods;
3146
+ }
3147
+ add_filter( 'wp_headers', 'remove_pingback_header' );
3148
+ function remove_pingback_header( $headers ) {
3149
+ unset( $headers['X-Pingback'] );
3150
+ return $headers;
3151
+ }
3152
+ }
3153
+ */
3154
+ //pingback_ping();
3155
+
3156
+
3157
+ /*
3158
+ // Remove shortlink from HEAD <link rel='shortlink' href='http://адрес-сайта/?p=45' />
3159
+ remove_action('wp_head', 'wp_shortlink_wp_head', 10, 0 );
3160
+ */
3161
+
3162
+ /**
3163
+ *
3164
+ * Send notification letter
3165
+ *
3166
+ * @param string $type Notification type
3167
+ * @param string|array $msg Additional message
3168
+ * @param string $ip Remote IP address, if applicable
3169
+ *
3170
+ * @return bool
3171
+ */
3172
+ function cerber_send_notify( $type = '', $msg = '', $ip = '' ) {
3173
+ global $wpdb, $wp_cerber;
3174
+ if ( ! $type ) {
3175
+ return false;
3176
+ }
3177
+
3178
+ /*
3179
+ $super = false;
3180
+ if ( function_exists( 'is_super_admin' ) ) {
3181
+ $super = is_super_admin();
3182
+ }
3183
+ if ( $type == 'lockout' && !$usper()) {
3184
+ */
3185
+
3186
+ if ( $type == 'lockout' && !is_admin()) {
3187
+ $rate = absint( $wp_cerber->getSettings( 'emailrate' ) );
3188
+ if ( $rate ) {
3189
+ $last = get_transient( 'cerber_last' );
3190
+ $period = 60 * 60; // per hour
3191
+ if ( $last ) {
3192
+ if ( $last > ( time() - $period / $rate ) ) {
3193
+ return false;
3194
+ }
3195
+ }
3196
+ set_transient( 'cerber_last', time(), $period );
3197
+ }
3198
+ }
3199
+
3200
+ $html_mode = false;
3201
+
3202
+ $subj = '[' . get_option( 'blogname' ) . '] ' . __( 'WP Cerber notify', 'wp-cerber' ) . ': ';
3203
+ $body = '';
3204
+
3205
+ if ( is_array( $msg ) ) {
3206
+ $msg = implode( "\n\n", $msg );
3207
+ }
3208
+
3209
+ switch ( $type ) {
3210
+ case 'citadel':
3211
+ $max = $wpdb->get_var( 'SELECT MAX(stamp) FROM ' . CERBER_LOG_TABLE . ' WHERE activity = 7' );
3212
+ if ($max) {
3213
+ $last_date = cerber_date( $max );
3214
+ $last = $wpdb->get_row( 'SELECT * FROM ' . CERBER_LOG_TABLE . ' WHERE stamp = ' . $max . ' AND activity = 7' );
3215
+ }
3216
+ else $last = null;
3217
+
3218
+ if ( ! $last ) { // workaround for the empty log table
3219
+ $last = new stdClass();
3220
+ $last->ip = '127.0.0.1';
3221
+ $last->user_login = 'test';
3222
+ }
3223
+
3224
+ $subj .= __( 'Citadel mode is activated', 'wp-cerber' );
3225
+
3226
+ $body = sprintf( __( 'Citadel mode is activated after %d failed login attempts in %d minutes.', 'wp-cerber' ), $wp_cerber->getSettings( 'cilimit' ), $wp_cerber->getSettings( 'ciperiod' ) ) . "\n\n";
3227
+ $body .= sprintf( __( 'Last failed attempt was at %s from IP %s with user login: %s.', 'wp-cerber' ), $last_date, $last->ip, $last->user_login ) . "\n\n";
3228
+ $body .= __( 'View activity in dashboard', 'wp-cerber' ) . ': ' . cerber_admin_link( 'activity' ) . "\n\n";
3229
+ //$body .= __('Change notification settings','wp-cerber').': '.cerber_admin_link();
3230
+ break;
3231
+ case 'lockout':
3232
+ $max = $wpdb->get_var( 'SELECT MAX(stamp) FROM ' . CERBER_LOG_TABLE . ' WHERE activity IN (10,11)' );
3233
+ if ($max){
3234
+ $last_date = cerber_date( $max );
3235
+ $last = $wpdb->get_row( 'SELECT * FROM ' . CERBER_LOG_TABLE . ' WHERE stamp = ' . $max . ' AND activity IN (10,11)' );
3236
+ }
3237
+ else $last = null;
3238
+ if ( ! $last ) { // workaround for the empty log table
3239
+ $last = new stdClass();
3240
+ $last->ip = '127.0.0.1';
3241
+ $last->user_login = 'test';
3242
+ }
3243
+
3244
+ //if ( ! $active = $wpdb->get_var( 'SELECT count(ip) FROM ' . CERBER_BLOCKS_TABLE ) ) {
3245
+ if ( ! $active = cerber_blocked_num() ) {
3246
+ $active = 0;
3247
+ }
3248
+ //if ( $ip && ( $block = cerber_get_block( $ip ) ) ) {
3249
+ if ( $last->ip && ( $block = cerber_get_block( $last->ip ) ) ) {
3250
+ $reason = $block->reason;
3251
+ }
3252
+ else {
3253
+ $reason = __( 'unspecified', 'wp-cerber' );
3254
+ }
3255
+
3256
+ $subj .= __( 'Number of lockouts is increasing', 'wp-cerber' ) . ' (' . $active . ')';
3257
+
3258
+ $body = __( 'Number of active lockouts', 'wp-cerber' ) . ': ' . $active . "\n\n";
3259
+ $body .= sprintf( __( 'Last lockout was added: %s for IP %s', 'wp-cerber' ), $last_date, $last->ip . ' (' . @gethostbyaddr( $last->ip ) . ')' ) . "\n\n";
3260
+ $body .= __( 'Reason', 'wp-cerber' ) . ': ' . strip_tags($reason) . "\n\n";
3261
+ $body .= __( 'View activity for this IP', 'wp-cerber' ) . ': ' . cerber_admin_link( 'activity' ) . '&filter_ip=' . $last->ip . "\n\n";
3262
+ $body .= __( 'View lockouts in dashboard', 'wp-cerber' ) . ': ' . cerber_admin_link( 'lockouts' ) . "\n\n";
3263
+ break;
3264
+ case 'new_version':
3265
+ $subj = __( 'A new version of WP Cerber is available to install', 'wp-cerber' );
3266
+ $body = __( 'Hi!', 'wp-cerber' ) . "\n\n";
3267
+ $body .= __( 'A new version of WP Cerber is available to install', 'wp-cerber' ) . "\n\n";
3268
+ $body .= $msg . "\n\n";
3269
+ $body .= __( 'Website', 'wp-cerber' ) . ': ' . get_bloginfo( 'name' );
3270
+ break;
3271
+ case 'shutdown':
3272
+ $subj = '[' . get_option( 'blogname' ) . '] ' . __( 'The WP Cerber security plugin has been deactivated', 'wp-cerber' );
3273
+ $body .= __( 'The WP Cerber security plugin has been deactivated', 'wp-cerber' ) . "\n\n";
3274
+ if ( ! is_user_logged_in() ) {
3275
+ $u = __( 'Not logged in', 'wp-cerber' );
3276
+ } else {
3277
+ $user = wp_get_current_user();
3278
+ $u = $user->display_name;
3279
+ }
3280
+ $body .= __( 'Website', 'wp-cerber' ) . ': ' . get_bloginfo( 'name' ) . "\n";
3281
+ $body .= __( 'By user', 'wp-cerber' ) . ': ' . $u . "\n";
3282
+ $body .= __( 'From IP address', 'wp-cerber' ) . ': ' . $wp_cerber->getRemoteIp() . "\n";
3283
+ $whois = cerber_ip_whois_info( $wp_cerber->getRemoteIp() );
3284
+ if ( ! empty( $whois['data']['country'] ) ) {
3285
+ $body .= __( 'From country', 'wp-cerber' ) . ': ' . cerber_country_name( $whois['data']['country'] );
3286
+ }
3287
+ break;
3288
+ case 'activated':
3289
+ $subj = '[' . get_option( 'blogname' ) . '] ' . __( 'The WP Cerber security plugin is now active', 'wp-cerber' );
3290
+ $body .= __( 'WP Cerber is now active and has started protecting your site', 'wp-cerber' ) . "\n\n";
3291
+ //$body .= __( 'Change notification settings', 'wp-cerber' ) . ': ' . cerber_admin_link('notifications') . "\n\n";
3292
+ $body .= __( 'Getting Started Guide', 'wp-cerber' ) . "\n\n";
3293
+ $body .= 'https://wpcerber.com/getting-started/' . "\n\n";
3294
+ $body .= 'Be in touch with the developer. Subscribe to Cerber\'s newsletter: http://wpcerber.com/subscribe-newsletter/';
3295
+ //$body .= get_bloginfo( 'name' );
3296
+ break;
3297
+ case 'newlurl':
3298
+ $subj .= __( 'New Custom login URL', 'wp-cerber' );
3299
+ $body .= $msg;
3300
+ break;
3301
+ case 'subs':
3302
+ $subj .= __( 'A new activity has been recorded', 'wp-cerber' );
3303
+ $body = __( 'A new activity has been recorded', 'wp-cerber' ) . "\n\n";
3304
+ $body .= $msg;
3305
+ break;
3306
+ case 'report':
3307
+ $html_mode = true;
3308
+ $subj = '[' . get_option( 'blogname' ) . '] WP Cerber Security: ' . __( 'Weekly report', 'wp-cerber' );
3309
+ $body = cerber_generate_report();
3310
+ $link = cerber_admin_link( 'notifications' );
3311
+ $body .= '<br/>' . __( 'To change reporting settings visit', 'wp-cerber' ) . ' <a href="' . $link . '">' . $link . '</a>';
3312
+ if ($msg) {
3313
+ $body .= nl2br($msg);
3314
+ }
3315
+ break;
3316
+ }
3317
+
3318
+ $to_list = cerber_get_email( $type, true );
3319
+ $to = implode( ', ', $to_list );
3320
+
3321
+ $body_filtered = apply_filters( 'cerber_notify_body', $body, array( 'type' => $type,
3322
+ 'IP' => $ip,
3323
+ 'to' => $to,
3324
+ 'subject' => $subj
3325
+ ) );
3326
+ if ( $body_filtered && is_string( $body_filtered ) ) {
3327
+ $body = $body_filtered;
3328
+ }
3329
+
3330
+ $footer = '';
3331
+
3332
+ if ( $lolink = cerber_get_login_url() ) {
3333
+ $lourl = urldecode( $lolink );
3334
+ if ( $html_mode ) {
3335
+ $lourl = '<a href="' . $lolink . '">' . $lourl . '</a>';
3336
+ }
3337
+ $footer .= "\n\n" . __( 'Your login page:', 'wp-cerber' ) . ' ' . $lourl;
3338
+ }
3339
+
3340
+ if ( $type == 'report' && $date = lab_lab(true) ) {
3341
+ $footer .= "\n\n" . __( 'Your license is valid until', 'wp-cerber' ) . ' ' . $date;
3342
+ }
3343
+
3344
+ $footer .= "\n\n\n" . __( 'This message was sent by', 'wp-cerber' ) . ' WP Cerber Security ' . CERBER_VER . "\n";
3345
+ $footer .= 'https://wpcerber.com';
3346
+
3347
+ if ( $html_mode ) {
3348
+ add_filter( 'wp_mail_content_type', 'cerber_enable_html' );
3349
+ $footer = str_replace( "\n", '<br/>', $footer );
3350
+ }
3351
+
3352
+ // Everything is prepared, let's send it out
3353
+
3354
+ $result = null;
3355
+ if ( $to && $subj && $body ) {
3356
+ if ( ! $html_mode ) {
3357
+ cerber_pb_send( $subj, $body.$footer );
3358
+ }
3359
+
3360
+ if ( $type == 'report') {
3361
+ $result = true;
3362
+ foreach ( $to_list as $email ) {
3363
+ $lastus = '';
3364
+ if ( $rec = cerber_get_last_login( null, $email ) ) {
3365
+ $lastus = sprintf( __( 'Your last sign-in was %s from %s', 'wp-cerber' ), cerber_date( $rec->stamp ), $rec->ip . ' (' . cerber_country_name( $rec->country ) . ')' );
3366
+ if ( $html_mode ) {
3367
+ $lastus = '<br/><br/>' . $lastus;
3368
+ }
3369
+ else {
3370
+ $lastus = "\n\n" . $lastus;
3371
+ }
3372
+ }
3373
+
3374
+ if ( ! wp_mail( $email, $subj, '<html>' . $body . $lastus . $footer . '</html>' ) ) {
3375
+ $result = false;
3376
+ }
3377
+ }
3378
+ }
3379
+ else {
3380
+ if ( function_exists( 'wp_mail' ) ) {
3381
+ $body = $body . $footer;
3382
+ if ( $html_mode ) {
3383
+ $body = '<html>' . $body . '</html>';
3384
+ }
3385
+ $result = wp_mail( $to, $subj, $body );
3386
+ }
3387
+ }
3388
+ }
3389
+
3390
+ remove_filter('wp_mail_content_type', 'cerber_enable_html');
3391
+
3392
+ $params = array( 'type' => $type, 'IP' => $ip, 'to' => $to, 'subject' => $subj );
3393
+ if ( $result ) {
3394
+ do_action( 'cerber_notify_sent', $body, $params );
3395
+ }
3396
+ else {
3397
+ do_action( 'cerber_notify_fail', $body, $params );
3398
+ }
3399
+
3400
+ return $result;
3401
+ }
3402
+
3403
+ function cerber_enable_html() {
3404
+ return 'text/html';
3405
+ }
3406
+
3407
+ /**
3408
+ * Generates a performance report
3409
+ *
3410
+ * @param int $period Days to look back
3411
+ *
3412
+ * @return string
3413
+ */
3414
+ function cerber_generate_report($period = 7){
3415
+ global $wpdb;
3416
+
3417
+ $period = absint( $period );
3418
+
3419
+ if ( ! $period ) {
3420
+ $period = 7;
3421
+ }
3422
+
3423
+ $ret = '';
3424
+ $rows = array();
3425
+ $stamp = time() - $period * 24 * 3600;
3426
+ //$in = implode( ',', crb_get_activity_set( 'malicious' ) );
3427
+ //$link_base = '<a href="' . cerber_activity_link( array( 2 ) ) . '">';
3428
+ $base_url = cerber_admin_link( 'activity' );
3429
+ $css_table = 'width: 95%; max-width: 1000px; margin:0 auto; margin-bottom: 10px; background-color: #f5f5f5; text-align: center;';
3430
+ $css_td = 'padding: 0.5em 0.5em 0.5em 1em; text-align: left;';
3431
+ $css_boder = 'border-bottom: solid 2px #f9f9f9;';
3432
+
3433
+ if (is_multisite()) {
3434
+ $site_name = get_site_option( 'site_name' );
3435
+ }
3436
+ else {
3437
+ $site_name = get_option( 'blogname' );
3438
+ }
3439
+
3440
+ $ret .= '<div style="' . $css_table . '"><div style="margin:0 auto; text-align: center;"><p style="font-size: 130%; padding-top: 0.5em;">' . $site_name .'</p><p style="padding-bottom: 1em;">'. __('Weekly Report','wp-cerber'). '</p></div></div>';
3441
+
3442
+ $kpi_list = cerber_calculate_kpi( $period );
3443
+
3444
+ foreach ($kpi_list as $kpi){
3445
+ $rows[] = '<td style="'.$css_td.' text-align: right;">'.$kpi[1].'</td><td style="padding: 0.5em; text-align: left;">'.$kpi[0].'</td>';
3446
+ }
3447
+
3448
+ $ret .= '<div style="text-align: center; '.$css_table.'"><table style="font-size: 130%; margin:0 auto;"><tr>' . implode( '</tr><tr>', $rows ) . '</tr></table></div>';
3449
+
3450
+ // Activities counters
3451
+ $rows = array();
3452
+ $rows[] = '<td style="'.$css_td.$css_boder.'" colspan="2"><p style="line-height: 1.5em; font-weight: bold;">'.__('Activity details','wp-cerber').'</p></td>';
3453
+ $activites = $wpdb->get_results( 'SELECT activity, COUNT(activity) cnt FROM ' . CERBER_LOG_TABLE . ' WHERE stamp > ' . $stamp . ' GROUP by activity ORDER BY cnt DESC' );
3454
+ if ( $activites ) {
3455
+ $lables = cerber_get_labels();
3456
+ foreach ( $activites as $a ) {
3457
+ $rows[] = '<td style="'.$css_boder.$css_td.'">' . $lables[ $a->activity ] . '</td><td style="padding: 0.5em; text-align: center; width:10%;'.$css_boder.'"><a href="'.$base_url.'&filter_activity='.$a->activity.'">' . $a->cnt . '</a></td>';
3458
+ }
3459
+ }
3460
+ $ret .= '<table style="border-collapse: collapse; '.$css_table.'"><tr>' . implode( '</tr><tr>', $rows ) . '</tr></table>';
3461
+
3462
+ // Activities counters
3463
+ $activites = $wpdb->get_results( 'SELECT user_login, COUNT(user_login) cnt FROM ' . CERBER_LOG_TABLE . ' WHERE activity = 51 AND stamp > ' . $stamp . ' GROUP by user_login ORDER BY cnt DESC LIMIT 10' );
3464
+ if ( $activites ) {
3465
+ $rows = array();
3466
+ $rows[] = '<td style="'.$css_td.$css_boder.'" colspan="2"><p style="line-height: 1.5em; font-weight: bold;">'.__('Attempts to log in with non-existent username','wp-cerber').'</p></td>';
3467
+ foreach ( $activites as $a ) {
3468
+ $rows[] = '<td style="'.$css_boder.$css_td.'">' . htmlspecialchars($a->user_login) . '</td><td style="padding: 0.5em; text-align: center; width:10%;'.$css_boder.'"><a href="'.$base_url.'&filter_login='.$a->user_login.'">' . $a->cnt . '</a></td>';
3469
+ }
3470
+ $ret .= '<table style="border-collapse: collapse; '.$css_table.'"><tr>' . implode( '</tr><tr>', $rows ) . '</tr></table>';
3471
+ }
3472
+
3473
+ $ret = '<div style="width:100%; padding: 1em; text-align: center; background-color: #f9f9f9;">' . $ret . '</div>';
3474
+
3475
+ return $ret;
3476
+ }
3477
+
3478
+
3479
+ // Maintenance routines ----------------------------------------------------------------
3480
+
3481
+ function cerber_init_cron(){
3482
+ $next_hour = floor( ( time() + 3600 ) / 3600 ) * 3600;
3483
+
3484
+ if ( ! wp_next_scheduled( 'cerber_hourly_1' ) ) {
3485
+ wp_schedule_event( $next_hour + 600, 'hourly', 'cerber_hourly_1' );
3486
+ }
3487
+
3488
+ if ( ! wp_next_scheduled( 'cerber_hourly_2' ) ) {
3489
+ wp_schedule_event( $next_hour , 'hourly', 'cerber_hourly_2' );
3490
+ }
3491
+
3492
+ if ( ! wp_next_scheduled( 'cerber_daily' ) ) {
3493
+ wp_schedule_event( $next_hour + 3600, 'daily', 'cerber_daily' );
3494
+ }
3495
+ }
3496
+
3497
+ add_action( 'cerber_hourly_1', 'cerber_do_hourly' );
3498
+ function cerber_do_hourly($force = false) {
3499
+ global $wpdb, $wp_cerber;
3500
+
3501
+ if (is_multisite()) {
3502
+ if ( ! $force && get_site_transient( 'cerber_multisite' ) ) {
3503
+ return;
3504
+ }
3505
+ set_site_transient( 'cerber_multisite', 'executed', 3600 );
3506
+ }
3507
+
3508
+ if ( crb_get_settings( 'cerberlab' ) ) {
3509
+ lab_check_nodes();
3510
+ }
3511
+
3512
+ $time = time();
3513
+ $days = absint( crb_get_settings( 'keeplog' ) );
3514
+ if ( $days > 0 ) {
3515
+ $wpdb->query( 'DELETE FROM ' . CERBER_LOG_TABLE . ' WHERE stamp < ' . ( $time - $days * 24 * 3600 ) );
3516
+ }
3517
+ $days = absint( crb_get_settings( 'tikeeprec' ) );
3518
+ if ( $days > 0 ) {
3519
+ $wpdb->query( 'DELETE FROM ' . CERBER_TRAF_TABLE . ' WHERE stamp < ' . ( $time - $days * 24 * 3600 ) );
3520
+ }
3521
+
3522
+ if ( crb_get_settings( 'cerberlab' ) ) {
3523
+ cerber_push_lab();
3524
+ }
3525
+
3526
+ $wpdb->query( 'DELETE FROM ' . CERBER_LAB_IP_TABLE . ' WHERE expires < ' . $time );
3527
+
3528
+ if ( $wp_cerber->getSettings( 'trashafter-enabled') && absint($wp_cerber->getSettings('trashafter'))) {
3529
+ $list = get_comments( array( 'status' => 'spam' ) );
3530
+ if ( $list ) {
3531
+ $time = time() - DAY_IN_SECONDS * absint($wp_cerber->getSettings( 'trashafter' ));
3532
+ foreach ( $list as $item ) {
3533
+ if ( $time > strtotime( $item->comment_date_gmt ) ) {
3534
+ wp_trash_comment( $item->comment_ID );
3535
+ }
3536
+ }
3537
+ }
3538
+ }
3539
+
3540
+ cerber_up_data();
3541
+
3542
+ set_site_transient( 'crb_hourly_1', date( 'G' ) , 3600 );
3543
+ }
3544
+
3545
+ add_action( 'cerber_hourly_2', function () {
3546
+
3547
+ // Avoid multiple executions on a weird hosting
3548
+ if ( ( $hour = get_site_transient( 'crb_hourly_2' ) ) && $hour == date( 'G' ) ) {
3549
+ return;
3550
+ }
3551
+
3552
+ $gmt_offset = get_option( 'gmt_offset' ) * 3600;
3553
+
3554
+ if ( crb_get_settings( 'enable-report' )
3555
+ && date( 'w', time() + $gmt_offset ) == crb_get_settings( 'wreports-day' )
3556
+ && date( 'G', time() + $gmt_offset ) == crb_get_settings( 'wreports-time' )
3557
+ //&& ! get_site_transient( 'cerber_wreport' )
3558
+ ) {
3559
+ $result = cerber_send_notify( 'report' );
3560
+ //set_site_transient( 'cerber_wreport', 'sent', 7200 );
3561
+ update_site_option( '_cerber_report', array( time(), $result ) );
3562
+ }
3563
+
3564
+ cerber_watchdog( true );
3565
+
3566
+ set_site_transient( 'crb_hourly_2', date( 'G' ) , 3600 );
3567
+ });
3568
+
3569
+ add_action( 'cerber_daily', 'cerber_do_daily' );
3570
+ function cerber_do_daily() {
3571
+ global $wpdb, $wp_cerber;
3572
+
3573
+ cerber_do_hourly( true );
3574
+
3575
+ $time = time();
3576
+
3577
+ lab_trunc_push();
3578
+
3579
+ lab_validate_lic();
3580
+
3581
+ $wpdb->query( 'DELETE FROM ' . CERBER_LAB_NET_TABLE . ' WHERE expires < ' . $time );
3582
+
3583
+ $wpdb->query( 'OPTIMIZE TABLE ' . CERBER_LOG_TABLE );
3584
+ $wpdb->query( 'OPTIMIZE TABLE ' . CERBER_TRAF_TABLE );
3585
+ $wpdb->query( 'OPTIMIZE TABLE ' . CERBER_ACL_TABLE );
3586
+ $wpdb->query( 'OPTIMIZE TABLE ' . CERBER_BLOCKS_TABLE );
3587
+ $wpdb->query( 'OPTIMIZE TABLE ' . CERBER_LAB_TABLE );
3588
+ $wpdb->query( 'OPTIMIZE TABLE ' . CERBER_LAB_IP_TABLE );
3589
+ $wpdb->query( 'OPTIMIZE TABLE ' . CERBER_LAB_NET_TABLE );
3590
+
3591
+ if ( $new = cerber_check_version() ) {
3592
+ $history = get_site_option( '_cerber_notify_new' );
3593
+ if ( ! $history || ! is_array( $history ) ) {
3594
+ $history = array();
3595
+ }
3596
+ if ( ! in_array( $new['ver'], $history ) ) {
3597
+ if ( crb_get_settings( 'notify-new-ver' ) ) {
3598
+ cerber_send_notify( 'new_version', 'Read more: https://wpcerber.com/?plugin_version=' . $new['ver'] );
3599
+ }
3600
+ $history[] = $new['ver'];
3601
+ update_site_option( '_cerber_notify_new', $history );
3602
+ }
3603
+ }
3604
+
3605
+ // TODO: implement holding previous values for a while
3606
+ // cerber_antibot_gene();
3607
+ }
3608
+
3609
+ /**
3610
+ * Log activity
3611
+ *
3612
+ * @param int $activity Activity ID
3613
+ * @param string $login Login used or any additional information
3614
+ * @param int $user_id User ID
3615
+ * @param null $ip IP Address
3616
+ *
3617
+ * @return false|int
3618
+ * @since 3.0
3619
+ */
3620
+ function cerber_log( $activity, $login = '', $user_id = 0, $ip = null ) {
3621
+ global $wpdb, $user_ID, $cerber_logged;
3622
+ static $logged = array();
3623
+ $wp_cerber = get_wp_cerber();
3624
+
3625
+ $activity = absint( $activity );
3626
+
3627
+ if ( isset( $logged[ $activity ] ) ) {
3628
+ return false;
3629
+ }
3630
+ else {
3631
+ $logged[ $activity ] = true;
3632
+ }
3633
+
3634
+ $cerber_logged[ $activity ] = $activity;
3635
+
3636
+ //$wp_cerber->setProcessed();
3637
+
3638
+ if ( empty( $ip ) ) {
3639
+ $ip = $wp_cerber->getRemoteIp();
3640
+ }
3641
+ elseif ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
3642
+ return false;
3643
+ }
3644
+
3645
+ if ( cerber_is_ipv4( $ip ) ) {
3646
+ $ip_long = ip2long( $ip );
3647
+ }
3648
+ else {
3649
+ $ip_long = 1;
3650
+ }
3651
+
3652
+ if ( empty( $user_id ) ) {
3653
+ if ( $user_ID ) {
3654
+ $user_id = $user_ID;
3655
+ }
3656
+ else {
3657
+ $user_ID = 0;
3658
+ }
3659
+ }
3660
+
3661
+ $user_id = absint( $user_id );
3662
+
3663
+ $stamp = cerber_request_time();
3664
+
3665
+ $pos = strpos($_SERVER['REQUEST_URI'],'?');
3666
+ if ($pos) {
3667
+ $path = substr( $_SERVER['REQUEST_URI'], 0, $pos );
3668
+ }
3669
+ else {
3670
+ $path = $_SERVER['REQUEST_URI'];
3671
+ }
3672
+ $url = strip_tags($_SERVER['HTTP_HOST'] . $path);
3673
+
3674
+ $why = 0;
3675
+ if ($activity != 10 && $activity != 11) {
3676
+ $why = cerber_get_status($ip);
3677
+ }
3678
+
3679
+ $details = $why .'|0|0|0|'. $url;
3680
+
3681
+ $country = lab_get_country( $ip );
3682
+
3683
+ /*
3684
+ $ret = $wpdb->query( $wpdb->prepare( 'INSERT INTO ' . CERBER_LOG_TABLE . ' (ip, ip_long, user_login, user_id, stamp, activity, session_id, country, details) VALUES (%s,%d,%s,%d,%f,%d,%s,%s,%s)', $ip, $ip_long, $login, $user_id, $stamp, $activity, $wp_cerber->getSessionID(), $country, $details ) );
3685
+ if ( ! $ret ) {
3686
+ // workaround for a WP bugs like this: WP silently doesn't not insert a row into a table
3687
+ // https://core.trac.wordpress.org/ticket/32315
3688
+ $ret = $wpdb->insert( CERBER_LOG_TABLE, array(
3689
+ 'ip' => $ip,
3690
+ 'ip_long' => $ip_long,
3691
+ 'user_login' => $login,
3692
+ 'user_id' => $user_id,
3693
+ 'stamp' => $stamp,
3694
+ 'activity' => $activity,
3695
+ 'session_id' => $wp_cerber->getSessionID(),
3696
+ 'country' => $country,
3697
+ 'details' => $details,
3698
+ ), array( '%s', '%d', '%s', '%d', '%f', '%d' ) );
3699
+ }*/
3700
+
3701
+ // @since 6.3
3702
+ $login = cerber_real_escape( $login );
3703
+ $details = cerber_real_escape( $details );
3704
+ $ret = cerber_db_query('INSERT INTO ' . CERBER_LOG_TABLE . ' (ip, ip_long, user_login, user_id, stamp, activity, session_id, country, details)
3705
+ VALUES ("'.$ip.'",'.$ip_long.',"'.$login.'",'.$user_id.',"'.$stamp.'",'.$activity.',"'.$wp_cerber->getSessionID().'","'.$country.'","'.$details.'")' );
3706
+
3707
+ if ( ! $ret ) {
3708
+ cerber_watchdog();
3709
+ }
3710
+
3711
+ // Subscriptions - notifications for admin ---------------------------------------------------
3712
+
3713
+ $subs = cerber_get_site_option( '_cerber_subs' );
3714
+
3715
+ if (!empty($subs)) {
3716
+ foreach ( $subs as $hash => $sub ) {
3717
+
3718
+ // Loop through subscription parameters
3719
+ if ( ! empty( $sub[0] )) {
3720
+ if ( ! in_array( $activity, $sub[0] ) ) {
3721
+ continue;
3722
+ }
3723
+ }
3724
+ if ( ! empty( $sub[1] ) && $sub[1] != $user_id ) {
3725
+ continue;
3726
+ }
3727
+ if ( ! empty( $sub[3] ) && ( $ip_long < $sub[2] || $sub[3] < $ip_long ) ) {
3728
+ continue;
3729
+ }
3730
+ if ( ! empty( $sub[4] ) && $sub[4] != $ip ) {
3731
+ continue;
3732
+ }
3733
+ if ( ! empty( $sub[5] ) && $sub[5] != $login ) {
3734
+ continue;
3735
+ }
3736
+ if ( ! empty( $sub[6] ) && (false === strpos( $ip, $sub[6] )) && (false === mb_strpos( $login, $sub[6] )) ) {
3737
+ continue;
3738
+ }
3739
+
3740
+ // Some parameter(s) matched, prepare and send notification
3741
+
3742
+ $labels = cerber_get_labels( 'activity' );
3743
+
3744
+ $msg = __( 'Activity', 'wp-cerber' ) . ': ' . $labels[$activity] . "\n\n";
3745
+
3746
+ if ( $country ) {
3747
+ $coname = ' ('.cerber_country_name( $country ).')';
3748
+ }
3749
+ else {
3750
+ $coname = '';
3751
+ }
3752
+
3753
+ $msg .= __( 'IP', 'wp-cerber' ) . ': ' . $ip . $coname. "\n\n";
3754
+
3755
+ if ( $user_id && function_exists('get_userdata')) {
3756
+ $u = get_userdata( $user_id );
3757
+ $msg .= __( 'User', 'wp-cerber' ) . ': ' . $u->display_name . "\n\n";
3758
+ }
3759
+
3760
+ if ( $login ) {
3761
+ $msg .= __( 'Username used', 'wp-cerber' ) . ': ' . $login . "\n\n";
3762
+ }
3763
+
3764
+ if ( ! empty( $sub['6'] ) ) {
3765
+ $msg .= __( 'Search string', 'wp-cerber' ) . ': ' . $sub['6'] . "\n\n";
3766
+ }
3767
+
3768
+ // Link to the Activity admin page
3769
+ $args = cerber_subscribe_params();
3770
+ $i = 0;
3771
+ $link_params = '';
3772
+ foreach ($args as $arg => $val){
3773
+ if (is_array($sub[$i])){
3774
+ foreach ( $sub[ $i ] as $item ) {
3775
+ $link_params .= '&' . $arg . '[]=' . $item;
3776
+ }
3777
+ }
3778
+ else {
3779
+ $link_params .= '&' . $arg . '=' . $sub[ $i ];
3780
+ }
3781
+ $i++;
3782
+ }
3783
+ $link = cerber_admin_link( 'activity' ) . $link_params;
3784
+
3785
+ $msg .= __( 'View activity in dashboard', 'wp-cerber' ) . ': ' . $link;
3786
+ $msg .= "\n\n" . __( 'To unsubscribe click here', 'wp-cerber' ) . ': ' . cerber_admin_link( 'activity' ) . '&unsubscribeme=' . $hash;
3787
+
3788
+ cerber_send_notify( 'subs', $msg, $ip );
3789
+
3790
+ break; // Just one notification letter per event
3791
+ }
3792
+ }
3793
+
3794
+ if ( in_array( $activity, array( 16, 17, 40, 56 ) ) ) {
3795
+ lab_save_push( $ip, $activity, '' );
3796
+ }
3797
+
3798
+ return $ret;
3799
+ }
3800
+
3801
+ /**
3802
+ * Get records from the log
3803
+ *
3804
+ * @param array $activity
3805
+ * @param array $user
3806
+ * @param array $order
3807
+ * @param string $limit
3808
+ *
3809
+ * @return array|null
3810
+ */
3811
+ function cerber_get_log($activity = array(), $user = array(), $order = array(), $limit = ''){
3812
+ global $wpdb;
3813
+
3814
+ $where = array();
3815
+ if ($activity){
3816
+ $activity = array_map( 'absint', $activity );
3817
+ $where[] = 'activity IN ('.implode(', ',$activity).')';
3818
+ }
3819
+
3820
+ if ($user['email']){
3821
+ $user = get_user_by( 'email', $user['email'] );
3822
+ $where[] = 'user_id = ' . absint( $user->ID );
3823
+ }
3824
+ elseif ($user['id']){
3825
+ $where[] = 'user_id = '.absint($user['id']);
3826
+ }
3827
+
3828
+ $where_sql = '';
3829
+ if ( $where ) {
3830
+ $where_sql = ' WHERE ' . implode( ' AND ', $where );
3831
+ }
3832
+
3833
+ $order_sql = '';
3834
+ if ( $order ) {
3835
+ if ( ! empty( $order['DESC'] ) ) {
3836
+ $order_sql = ' ORDER BY ' . preg_replace( '/[^\w]/', '', $order['DESC'] ) . ' DESC ';
3837
+ }
3838
+ elseif ( ! empty( $order['ASC'] ) ) {
3839
+ $order_sql = ' ORDER BY ' . preg_replace( '/[^\w]/', '', $order['ASC'] ) . ' ASC ';
3840
+ }
3841
+ }
3842
+
3843
+ $limit_sql = '';
3844
+ if ( $limit ) {
3845
+ $limit_sql = ' LIMIT ' . preg_replace( '/[^0-9\.]/', '', $limit );
3846
+ }
3847
+
3848
+ // $row = $wpdb->get_row('SELECT * FROM '.CERBER_LOG_TABLE.' WHERE activity = 5 AND user_id = '.absint($user_id) . ' ORDER BY stamp DESC LIMIT 1');
3849
+ return $wpdb->get_results( 'SELECT * FROM ' . CERBER_LOG_TABLE . ' ' . $where_sql . $order_sql . $limit_sql );
3850
+
3851
+ }
3852
+
3853
+ /**
3854
+ * Return the last login record for a given user
3855
+ *
3856
+ * @param $user_id int|null
3857
+ * @param $user_email string
3858
+ *
3859
+ * @return array|null|object|string
3860
+ */
3861
+ function cerber_get_last_login( $user_id, $user_email = '' ) {
3862
+ if ( $user_id ) {
3863
+ $u = array( 'id' => $user_id );
3864
+ }
3865
+ elseif ( $user_email ) {
3866
+ $u = array( 'email' => $user_email );
3867
+ }
3868
+
3869
+ if ($u) {
3870
+ $recs = cerber_get_log( array( 5 ), $u, array( 'DESC' => 'stamp' ), 1 );
3871
+ return $recs[0];
3872
+ }
3873
+
3874
+ return '';
3875
+ }
3876
+
3877
+ function cerber_count_log($activity = array(), $period = 1) {
3878
+ global $wpdb;
3879
+
3880
+ $period = absint( $period );
3881
+ if ( ! $period ) {
3882
+ $period = 1;
3883
+ }
3884
+
3885
+ $stamp = time() - $period * 24 * 3600;
3886
+
3887
+ // TODO: replace with SELECT COUNT(DISTINCT session_id)
3888
+ $ret = $wpdb->get_var('SELECT COUNT(ip) FROM '. CERBER_LOG_TABLE .' WHERE activity IN ('.implode(',',$activity).') AND stamp > '. $stamp);
3889
+ if (!$ret) $ret = 0;
3890
+
3891
+ return $ret;
3892
+ }
3893
+
3894
+ /**
3895
+ * Create a set of parameters for using it in Subscriptions
3896
+ * The keys are used to built an URL. Values to calculate a hash.
3897
+ *
3898
+ * @return array The set of parameters
3899
+ */
3900
+ function cerber_subscribe_params() {
3901
+ $begin = 0;
3902
+ $end = 0;
3903
+ $ip = 0;
3904
+ if ( ! empty( $_GET['filter_ip'] ) ) {
3905
+ $ip = cerber_any2range( $_GET['filter_ip'] );
3906
+ if ( is_array( $ip ) ) {
3907
+ $begin = $ip['begin'];
3908
+ $end = $ip['end'];
3909
+ $ip = 0;
3910
+ } elseif ( ! $ip ) {
3911
+ $ip = 0;
3912
+ }
3913
+ }
3914
+
3915
+ $filter_activity = ( empty( $_GET['filter_activity'] ) ) ? 0 : $_GET['filter_activity'];
3916
+ $filter_user = ( empty( $_GET['filter_user'] ) ) ? 0 : $_GET['filter_user'];
3917
+ $filter_login = ( empty( $_GET['filter_login'] ) ) ? 0 : $_GET['filter_login'];
3918
+ $search_activity = ( empty( $_GET['search_activity'] ) ) ? 0 : $_GET['search_activity'];
3919
+ $filter_role = ( empty( $_GET['filter_role'] ) ) ? 0 : $_GET['filter_role'];
3920
+
3921
+ if ( ! is_array( $filter_activity ) ) {
3922
+ $filter_activity = array( $filter_activity );
3923
+ }
3924
+ $filter_activity = array_filter( $filter_activity );
3925
+
3926
+ // 'begin' and 'end' array keys are not used, added for compatibility
3927
+ return array( 'filter_activity' => $filter_activity, 'filter_user' => $filter_user, 'being' => $begin, 'end' => $end, 'filter_ip' => $ip, 'filter_login' => $filter_login, 'search_activity' => $search_activity, 'filter_role' => $filter_role );
3928
+ }
3929
+
3930
+ /*
3931
+ Plugin activation
3932
+ */
3933
+ //register_activation_hook( __FILE__, 'cerber_activate' );
3934
+ register_activation_hook( cerber_plugin_file(), 'cerber_activate' );
3935
+ function cerber_activate() {
3936
+ global $wp_version;
3937
+ $assets_url = cerber_plugin_dir_url() . 'assets';
3938
+
3939
+ //cerber_load_lang();
3940
+ load_plugin_textdomain( 'wp-cerber', false, basename( dirname( __FILE__ ) ) . '/languages' );
3941
+
3942
+ if ( version_compare( CERBER_REQ_PHP, phpversion(), '>' ) ) {
3943
+ cerber_stop_activating( '<h3>' . sprintf( __( 'The WP Cerber requires PHP %s or higher. You are running', 'wp-cerber' ), CERBER_REQ_PHP ) . ' ' . phpversion() . '</h3>' );
3944
+ }
3945
+
3946
+ if ( version_compare( CERBER_REQ_WP, $wp_version, '>' ) ) {
3947
+ cerber_stop_activating( '<h3>' . sprintf( __( 'The WP Cerber requires WordPress %s or higher. You are running', 'wp-cerber' ), CERBER_REQ_WP ) . ' ' . $wp_version . '</h3>' );
3948
+ }
3949
+
3950
+ $db_errors = cerber_create_db();
3951
+ if ( $db_errors ) {
3952
+ $e = '';
3953
+ foreach ( $db_errors as $db_error ) {
3954
+ $e .= '<p>' . implode( '</p><p>', $db_error ) . '</p>';
3955
+ }
3956
+ cerber_stop_activating( '<h3>' . __( "Can't activate WP Cerber due to a database error.", 'wp-cerber' ) . '</h3>'.$e);
3957
+ }
3958
+
3959
+ cerber_upgrade_all();
3960
+
3961
+ cerber_cookie1();
3962
+ cerber_disable_citadel();
3963
+ //cerber_get_groove();
3964
+
3965
+ $wp_cerber = get_wp_cerber();
3966
+
3967
+ cerber_add_white( cerber_get_subnet( $wp_cerber->getRemoteIp() ) , 'My subnet' ); // Protection for non-experienced user
3968
+
3969
+ cerber_htaccess_sync();
3970
+
3971
+ cerber_set_boot_mode();
3972
+
3973
+ cerber_admin_message(
3974
+ '<img style="float:left; margin-left:-10px;" src="' . $assets_url . '/icon-128x128.png">' .
3975
+ '<p style="font-size:120%;">' . __( 'WP Cerber is now active and has started protecting your site', 'wp-cerber' ) . '</p>' .
3976
+ ' <p>' . __( 'Your IP address is added to the', 'wp-cerber' ) . ' ' . __( 'White IP Access List', 'wp-cerber' ) .
3977
+
3978
+ ' <p style="font-size:120%;"><a href="http://wpcerber.com/getting-started/" target="_blank">' . __( 'Getting Started Guide', 'wp-cerber' ) . '</a></p>' .
3979
+
3980
+ //' <p><b>' . __( "It's important to check security settings.", 'wp-cerber' ) . '</b> &nbsp;<a href="http://wpcerber.com/" target="_blank">Read Cerber\'s blog</a> ' .
3981
+ //'&nbsp; <a href="http://wpcerber.com/subscribe-newsletter/" target="_blank">Subscribe to Cerber\'s newsletter</a></p>' .
3982
+
3983
+ ' <p> </p><p><span class="dashicons dashicons-admin-settings"></span> <a href="' . cerber_admin_link( 'main' ) . '">' . __( 'Main Settings', 'wp-cerber' ) . '</a>' .
3984
+ ' <span style="margin-left:20px;" class="dashicons dashicons-admin-network"></span> <a href="' . cerber_admin_link( 'acl' ) . '">' . __( 'Access Lists', 'wp-cerber' ) . '</a>' .
3985
+ ' <span style="margin-left:20px;" class="dashicons dashicons-forms"></span> <a href="' . cerber_admin_link( 'antispam' ) . '">' . __( 'Antispam', 'wp-cerber' ) . '</a>' .
3986
+ ' <span style="margin-left:20px;" class="dashicons dashicons-shield-alt"></span> <a href="' . cerber_admin_link( 'hardening' ) . '">' . __( 'Hardening', 'wp-cerber' ) . '</a>' .
3987
+ ' <span style="margin-left:20px;" class="dashicons dashicons-controls-volumeon"></span> <a href="' . cerber_admin_link( 'notifications' ) . '">' . __( 'Notifications', 'wp-cerber' ) . '</a>' .
3988
+ ' <span style="margin-left:20px;" class="dashicons dashicons-admin-tools"></span> <a href="' . cerber_admin_link( 'imex' ) . '">' . __( 'Import settings', 'wp-cerber' ) . '</a>' .
3989
+ '</p>' );
3990
+
3991
+
3992
+ // Check for existing options
3993
+ $opt = cerber_get_options();
3994
+
3995
+ if ( !empty( $opt ) && is_array( $opt ) ) {
3996
+ $opt = array_filter( $opt );
3997
+ if ( ! empty( $opt ) ) {
3998
+ return;
3999
+ }
4000
+ }
4001
+
4002
+ cerber_load_defaults();
4003
+
4004
+ cerber_send_notify( 'activated' );
4005
+
4006
+ $pi = get_file_data( cerber_plugin_file(), array( 'Version' => 'Version' ), 'plugin' );
4007
+ $pi ['time'] = time();
4008
+ $pi ['user'] = get_current_user_id();
4009
+ update_site_option( '_cerber_activated', $pi );
4010
+ }
4011
+
4012
+ /*
4013
+ Abort activating plugin!
4014
+ */
4015
+ function cerber_stop_activating( $msg ) {
4016
+ //deactivate_plugins( plugin_basename( __FILE__ ) );
4017
+ deactivate_plugins( cerber_plug_in() );
4018
+ wp_die( $msg );
4019
+ }
4020
+
4021
+ /**
4022
+ * Upgrade database tables, data and plugin settings
4023
+ *
4024
+ * @since 3.0
4025
+ *
4026
+ */
4027
+ function cerber_upgrade_all() {
4028
+ $ver = cerber_get_site_option( '_cerber_up' );
4029
+ if ( ! $ver || $ver['v'] != CERBER_VER ) {
4030
+ cerber_create_db();
4031
+ cerber_upgrade_db();
4032
+ cerber_acl_fixer( true );
4033
+ cerber_push_the_news( CERBER_VER );
4034
+ cerber_antibot_gene( true );
4035
+ cerber_upgrade_options();
4036
+ wp_clear_scheduled_hook( 'cerber_hourly' ); // @since 5.8
4037
+ update_site_option( '_cerber_up', array( 'v' => CERBER_VER, 't' => time() ) );
4038
+ }
4039
+ }
4040
+
4041
+ /**
4042
+ * Creates DB tables if they don't exist
4043
+ *
4044
+ * @param bool $recreate If true, recreate some tables completely (with data lost)
4045
+ *
4046
+ * @return array Errors
4047
+ */
4048
+ function cerber_create_db($recreate = true) {
4049
+ global $wpdb;
4050
+
4051
+ $wpdb->hide_errors();
4052
+ $db_errors = array();
4053
+ $sql = array();
4054
+
4055
+ if (!cerber_is_table(CERBER_LOG_TABLE)){
4056
+ $sql[] = "
4057
+ CREATE TABLE IF NOT EXISTS " . CERBER_LOG_TABLE . " (
4058
+ ip varchar(39) CHARACTER SET ascii NOT NULL COMMENT 'Remote IP',
4059
+ user_login varchar(60) NOT NULL COMMENT 'Username from HTTP request',
4060
+ user_id bigint(20) unsigned NOT NULL DEFAULT '0',
4061
+ stamp bigint(20) unsigned NOT NULL COMMENT 'Unix timestamp',
4062
+ activity int(10) unsigned NOT NULL DEFAULT '0',
4063
+ KEY ip (ip)
4064
+ ) DEFAULT CHARSET=utf8 COMMENT='Cerber activity log';
4065
+ ";
4066
+ }
4067
+
4068
+ if (!cerber_is_table(CERBER_ACL_TABLE)){
4069
+ $sql[] = "
4070
+ CREATE TABLE IF NOT EXISTS " . CERBER_ACL_TABLE . " (
4071
+ ip varchar(39) CHARACTER SET ascii NOT NULL COMMENT 'IP',
4072
+ tag char(1) NOT NULL COMMENT 'Type: B or W',
4073
+ comments varchar(250) NOT NULL,
4074
+ UNIQUE KEY ip (ip)
4075
+ ) DEFAULT CHARSET=utf8 COMMENT='Cerber IP Access Lists';
4076
+ ";
4077
+ }
4078
+
4079
+ if (!cerber_is_table(CERBER_BLOCKS_TABLE)){
4080
+ $sql[] = "
4081
+ CREATE TABLE IF NOT EXISTS " . CERBER_BLOCKS_TABLE . " (
4082
+ ip varchar(39) CHARACTER SET ascii NOT NULL COMMENT 'Remote IP',
4083
+ block_until bigint(20) unsigned NOT NULL COMMENT 'Unix timestamp',
4084
+ reason varchar(250) NOT NULL COMMENT 'Why IP was blocked',
4085
+ UNIQUE KEY ip (ip)
4086
+ ) DEFAULT CHARSET=utf8 COMMENT='Cerber list of currently blocked IPs';
4087
+ ";
4088
+ }
4089
+
4090
+ if (!cerber_is_table(CERBER_LAB_TABLE)){
4091
+ $sql[] = "
4092
+ CREATE TABLE IF NOT EXISTS " . CERBER_LAB_TABLE . " (
4093
+ ip varchar(39) CHARACTER SET ascii NOT NULL COMMENT 'Remote IP',
4094
+ reason_id int(11) unsigned NOT NULL DEFAULT '0',
4095
+ stamp bigint(20) unsigned NOT NULL COMMENT 'Unix timestamp',
4096
+ details text NOT NULL
4097
+ ) DEFAULT CHARSET=utf8 COMMENT='Cerber lab cache';
4098
+ ";
4099
+ }
4100
+
4101
+
4102
+ if ($recreate || !cerber_is_table(CERBER_LAB_IP_TABLE)){
4103
+ if ( $recreate && cerber_is_table( CERBER_LAB_IP_TABLE ) ) {
4104
+ $sql[] = 'DROP TABLE IF EXISTS ' . CERBER_LAB_IP_TABLE;
4105
+ }
4106
+ $sql[] = "
4107
+ CREATE TABLE IF NOT EXISTS " . CERBER_LAB_IP_TABLE . " (
4108
+ ip varchar(39) CHARACTER SET ascii NOT NULL COMMENT 'IP',
4109
+ reputation INT(11) UNSIGNED NOT NULL COMMENT 'Reputation of IP',
4110
+ expires INT(11) UNSIGNED NOT NULL COMMENT 'Unix timestamp',
4111
+ PRIMARY KEY (ip)
4112
+ ) DEFAULT CHARSET=utf8 COMMENT='Cerber lab IP cache';
4113
+ ";
4114
+ }
4115
+
4116
+ if ( $recreate || ! cerber_is_table( CERBER_LAB_NET_TABLE ) ) {
4117
+ if ( $recreate && cerber_is_table( CERBER_LAB_NET_TABLE ) ) {
4118
+ $sql[] = 'DROP TABLE IF EXISTS ' . CERBER_LAB_NET_TABLE;
4119
+ }
4120
+ $sql[] = '
4121
+ CREATE TABLE IF NOT EXISTS ' . CERBER_LAB_NET_TABLE . ' (
4122
+ ip varchar(39) CHARACTER SET ascii NOT NULL DEFAULT "" COMMENT "IP address",
4123
+ ip_long_begin BIGINT UNSIGNED NOT NULL DEFAULT "0",
4124
+ ip_long_end BIGINT UNSIGNED NOT NULL DEFAULT "0",
4125
+ country CHAR(3) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL DEFAULT "" COMMENT "Country code",
4126
+ expires INT(11) UNSIGNED NOT NULL DEFAULT "0",
4127
+ PRIMARY KEY (ip),
4128
+ UNIQUE KEY begin_end (ip_long_begin, ip_long_end)
4129
+ ) DEFAULT CHARSET=utf8 COMMENT="Cerber lab network cache";
4130
+ ';
4131
+ }
4132
+
4133
+ if (!cerber_is_table(CERBER_GEO_TABLE)){
4134
+ $sql[] = '
4135
+ CREATE TABLE IF NOT EXISTS ' . CERBER_GEO_TABLE . ' (
4136
+ country CHAR(3) NOT NULL DEFAULT "" COMMENT "Country code",
4137
+ locale CHAR(10) NOT NULL DEFAULT "" COMMENT "Locale i18n",
4138
+ country_name VARCHAR(250) NOT NULL DEFAULT "" COMMENT "Country name",
4139
+ PRIMARY KEY (country, locale)
4140
+ ) DEFAULT CHARSET=utf8;
4141
+ ';
4142
+ }
4143
+
4144
+ if (!cerber_is_table(CERBER_TRAF_TABLE)){
4145
+ $sql[] = '
4146
+ CREATE TABLE IF NOT EXISTS ' . CERBER_TRAF_TABLE . ' (
4147
+ ip varchar(39) CHARACTER SET ascii NOT NULL,
4148
+ ip_long BIGINT UNSIGNED NOT NULL DEFAULT "0",
4149
+ hostname varchar(250) NOT NULL DEFAULT "",
4150
+ uri text NOT NULL,
4151
+ request_fields MEDIUMTEXT NOT NULL,
4152
+ request_details MEDIUMTEXT NOT NULL,
4153
+ session_id char(32) CHARACTER SET ascii NOT NULL,
4154
+ user_id bigint(20) UNSIGNED NOT NULL DEFAULT 0,
4155
+ stamp decimal(14,4) NOT NULL,
4156
+ processing int(10) NOT NULL DEFAULT 0,
4157
+ country char(3) CHARACTER SET ascii NOT NULL DEFAULT "",
4158
+ request_method char(8) CHARACTER SET ascii NOT NULL,
4159
+ http_code int(10) UNSIGNED NOT NULL,
4160
+ wp_id bigint(20) UNSIGNED NOT NULL DEFAULT 0,
4161
+ wp_type int(10) UNSIGNED NOT NULL DEFAULT 0,
4162
+ is_bot int(10) UNSIGNED NOT NULL DEFAULT 0,
4163
+ blog_id int(10) UNSIGNED NOT NULL DEFAULT 0,
4164
+ KEY stamp (stamp)
4165
+ ) DEFAULT CHARSET=utf8;
4166
+ ';
4167
+ }
4168
+
4169
+ foreach ( $sql as $query ) {
4170
+ if ( ! $wpdb->query( $query ) && $wpdb->last_error ) {
4171
+ $db_errors[] = array( $wpdb->last_error, $wpdb->last_query );
4172
+ }
4173
+ }
4174
+
4175
+ return $db_errors;
4176
+ }
4177
+
4178
+ /**
4179
+ * Upgrade structure of existing DB tables
4180
+ *
4181
+ * @return array Errors during upgrading
4182
+ * @since 3.0
4183
+ */
4184
+ function cerber_upgrade_db( $force = false ) {
4185
+ global $wpdb;
4186
+ $wpdb->hide_errors();
4187
+ if ($force) $wpdb->suppress_errors();
4188
+ $db_errors = array();
4189
+ $sql = array();
4190
+
4191
+ // @since 3.0
4192
+ $sql[] = 'ALTER TABLE ' . CERBER_LOG_TABLE . ' CHANGE stamp stamp DECIMAL(14,4) NOT NULL';
4193
+
4194
+ // @since 3.1
4195
+ if ( $force || ! cerber_is_column( CERBER_LOG_TABLE, 'ip_long' ) ) {
4196
+ $sql[] = 'ALTER TABLE ' . CERBER_LOG_TABLE . ' ADD ip_long BIGINT UNSIGNED NOT NULL DEFAULT "0" COMMENT "IPv4 long" AFTER ip, ADD INDEX (ip_long)';
4197
+ }
4198
+ if ( $force || ! cerber_is_column( CERBER_ACL_TABLE, 'ip_long_begin' ) ) {
4199
+ $sql[] = 'ALTER TABLE ' . CERBER_ACL_TABLE . " ADD ip_long_begin BIGINT UNSIGNED NOT NULL DEFAULT '0' COMMENT 'IPv4 range begin' AFTER ip, ADD ip_long_end BIGINT UNSIGNED NOT NULL DEFAULT '0' COMMENT 'IPv4 range end' AFTER ip_long_begin";
4200
+ }
4201
+ if ( $force || !cerber_is_index( CERBER_ACL_TABLE, 'ip_begin_end' ) ) {
4202
+ $sql[] = 'ALTER TABLE ' . CERBER_ACL_TABLE . ' ADD UNIQUE ip_begin_end (ip, ip_long_begin, ip_long_end)';
4203
+ }
4204
+ if ( $force || cerber_is_index( CERBER_ACL_TABLE, 'ip' ) ) {
4205
+ $sql[] = 'ALTER TABLE ' . CERBER_ACL_TABLE . ' DROP INDEX ip';
4206
+ }
4207
+
4208
+ // @since 4.8.2
4209
+ if ( $force || cerber_is_index( CERBER_ACL_TABLE, 'begin_end' ) ) {
4210
+ $sql[] = 'ALTER TABLE ' . CERBER_ACL_TABLE . ' DROP INDEX begin_end';
4211
+ }
4212
+ if ( $force || !cerber_is_index( CERBER_ACL_TABLE, 'begin_end_tag' ) ) {
4213
+ $sql[] = 'ALTER TABLE ' . CERBER_ACL_TABLE . ' ADD INDEX begin_end_tag (ip_long_begin, ip_long_end, tag)';
4214
+ }
4215
+
4216
+ // @since 4.9
4217
+ if ( $force || ! cerber_is_column( CERBER_LOG_TABLE, 'session_id' ) ) {
4218
+ $sql[] = 'ALTER TABLE ' . CERBER_LOG_TABLE . '
4219
+ ADD session_id CHAR(32) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL DEFAULT "",
4220
+ ADD country CHAR(3) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL DEFAULT "" COMMENT "Country code",
4221
+ ADD details VARCHAR(250) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL DEFAULT "" COMMENT "Details about HTTP request";
4222
+ ';
4223
+ }
4224
+
4225
+ // @since 6.1
4226
+ if ( $force || !cerber_is_index( CERBER_LOG_TABLE, 'session_index' ) ) {
4227
+ $sql[] = 'ALTER TABLE ' . CERBER_LOG_TABLE . ' ADD INDEX session_index (session_id)';
4228
+ }
4229
+
4230
+ if (!empty($sql)) {
4231
+ foreach ( $sql as $query ) {
4232
+ if ( !$wpdb->query( $query ) && $wpdb->last_error ) {
4233
+ $db_errors[] = array( $wpdb->last_error, $wpdb->last_query );
4234
+ }
4235
+ }
4236
+ }
4237
+
4238
+ // Convert existing data into the new format
4239
+
4240
+ cerber_acl_fixer();
4241
+
4242
+ if ( $db_errors ) {
4243
+ update_site_option( '_cerber_db_errors', $db_errors );
4244
+ }
4245
+ else {
4246
+ update_site_option( '_cerber_db_errors', '' );
4247
+ }
4248
+
4249
+ return $db_errors;
4250
+ }
4251
+
4252
+ /**
4253
+ * Updating old activity log records to the new row format (has been introduced in v 3.1)
4254
+ *
4255
+ * @since 4.0
4256
+ *
4257
+ */
4258
+ function cerber_up_data() {
4259
+ global $wpdb;
4260
+ $ips = $wpdb->get_col( 'SELECT DISTINCT ip FROM ' . CERBER_LOG_TABLE . ' WHERE ip_long = 0 LIMIT 50' );
4261
+ if ( ! $ips ) {
4262
+ return;
4263
+ }
4264
+ foreach ( $ips as $ip ) {
4265
+ if ( cerber_is_ipv4( $ip ) ) {
4266
+ $ip_long = ip2long( $ip );
4267
+ } else {
4268
+ $ip_long = 1;
4269
+ }
4270
+ $wpdb->query( 'UPDATE ' . CERBER_LOG_TABLE . ' SET ip_long = ' . $ip_long . ' WHERE ip = "' . $ip .'" AND ip_long = 0');
4271
+ }
4272
+ }
4273
+
4274
+ /**
4275
+ * Upgrade corrupted / from older versions of the plugin rows in ACL
4276
+ *
4277
+ * @param bool $ipv6 if true Process IPv6 addresses
4278
+ *
4279
+ */
4280
+ function cerber_acl_fixer($ipv6 = false){
4281
+ global $wpdb;
4282
+
4283
+ // Repair/update IPs without long values
4284
+ $rows = $wpdb->get_col( 'SELECT ip FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin = 0 OR ip_long_end = 0' );
4285
+ if ( ! $rows ) {
4286
+ return;
4287
+ }
4288
+ foreach ( $rows as $ip ) {
4289
+ if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) ) {
4290
+ continue;
4291
+ }
4292
+ $range = cerber_any2range( $ip );
4293
+ if ( is_array( $range ) ) {
4294
+ $begin = $range['begin'];
4295
+ $end = $range['end'];
4296
+ }
4297
+ else {
4298
+ $begin = ip2long( $ip );
4299
+ $end = ip2long( $ip );
4300
+ }
4301
+
4302
+ $wpdb->query( 'UPDATE ' . CERBER_ACL_TABLE . ' SET ip_long_begin = ' . $begin . ', ip_long_end = ' . $end . ' WHERE ip = "' . $ip .'"');
4303
+ }
4304
+
4305
+ // Convert old IPv6 to all shortened
4306
+ if ( $ipv6 ) {
4307
+ $ips = $wpdb->get_col( 'SELECT ip FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin = 0' );
4308
+ if ( $ips ) {
4309
+ foreach ( $ips as $ip ) {
4310
+ if ( ! filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) ) {
4311
+ continue;
4312
+ }
4313
+ $short_ip = cerber_short_ipv6( $ip );
4314
+ if ($short_ip != $ip) {
4315
+ $wpdb->query( 'UPDATE ' . CERBER_ACL_TABLE . ' SET ip = "' . $short_ip . '" WHERE ip = "' . $ip . '"' );
4316
+ }
4317
+ }
4318
+ }
4319
+ }
4320
+ }
4321
+
4322
+ add_action( 'deac' . 'tivate_' . cerber_plug_in(), 'cerber_clean' );
4323
+ function cerber_clean( $ip ) {
4324
+ wp_clear_scheduled_hook( 'cerber_hourly_1' );
4325
+ wp_clear_scheduled_hook( 'cerber_hourly_2' );
4326
+ wp_clear_scheduled_hook( 'cerber_daily' );
4327
+
4328
+ cerber_htaccess_clean_up();
4329
+ cerber_set_boot_mode( 0 );
4330
+
4331
+ $pi = get_file_data( cerber_plugin_file(), array( 'Version' => 'Version' ), 'plugin' );
4332
+ $pi ['v'] = time();
4333
+ $pi ['u'] = get_current_user_id();
4334
+ update_site_option( '_cerber_o' . 'ff', $pi );
4335
+ $f = 'cerb' . 'er_se' . 'nd_not' . 'ify';
4336
+ $f( 'sh' . 'utd' . 'own' );
4337
+ }
4338
+
4339
+ /*
4340
+ Fix an issue with the empty user_id field in the comments table.
4341
+ */
4342
+ add_filter( 'preprocess_comment', 'cerber_add_uid' );
4343
+ function cerber_add_uid( $commentdata ) {
4344
+ $current_user = wp_get_current_user();
4345
+ $commentdata['user_ID'] = $current_user->ID;
4346
+
4347
+ return $commentdata;
4348
+ }
4349
+
4350
+ /**
4351
+ * Load jQuery on the page
4352
+ *
4353
+ */
4354
+ add_action( 'login_enqueue_scripts', 'cerber_login_scripts' );
4355
+ function cerber_login_scripts() {
4356
+ if ( cerber_antibot_enabled( array('botsreg', 'botsany') ) ) {
4357
+ wp_enqueue_script( 'jquery' );
4358
+ }
4359
+ }
4360
+ add_action( 'wp_enqueue_scripts', 'cerber_scripts' );
4361
+ function cerber_scripts() {
4362
+ global $wp_cerber;
4363
+ if ( ( is_singular() && cerber_antibot_enabled( array( 'botscomm', 'botsany' ) ) )
4364
+ || ( $wp_cerber->getSettings( 'sitekey' ) && $wp_cerber->getSettings( 'secretkey' ) )
4365
+ ) {
4366
+ wp_enqueue_script( 'jquery' );
4367
+ }
4368
+ }
4369
+
4370
+ /**
4371
+ * Footer stuff
4372
+ * Explicit rendering reCAPTCHA
4373
+ *
4374
+ */
4375
+ add_action( 'login_footer', 'cerber_login_foo', 1000 );
4376
+ function cerber_login_foo( $ip ) {
4377
+ global $wp_cerber;
4378
+
4379
+ cerber_antibot_code(array( 'botsreg', 'botsany' ));
4380
+
4381
+ // Universal JS
4382
+ if (!$wp_cerber->recaptcha_here) return;
4383
+
4384
+ $sitekey = $wp_cerber->getSettings('sitekey');
4385
+
4386
+ if (!$wp_cerber->getSettings('invirecap')){
4387
+ // Classic version (visible reCAPTCHA)
4388
+ echo '<script src = https://www.google.com/recaptcha/api.js?hl='.cerber_recaptcha_lang().' async defer></script>';
4389
+ }
4390
+ else {
4391
+ // Pure JS version with explicit rendering
4392
+ ?>
4393
+ <script src="https://www.google.com/recaptcha/api.js?onload=init_recaptcha_widgets&render=explicit&hl=<?php echo cerber_recaptcha_lang(); ?>" async defer></script>
4394
+ <script type='text/javascript'>
4395
+
4396
+ document.getElementById("cerber-recaptcha").remove();
4397
+
4398
+ var init_recaptcha_widgets = function () {
4399
+ for (var i = 0; i < document.forms.length; ++i) {
4400
+ var form = document.forms[i];
4401
+ var place = form.querySelector('.cerber-form-marker');
4402
+ if (null !== place) render_recaptcha_widget(form, place);
4403
+ }
4404
+ };
4405
+
4406
+ function render_recaptcha_widget(form, place) {
4407
+ var place_id = grecaptcha.render(place, {
4408
+ 'callback': function (g_recaptcha_response) {
4409
+ HTMLFormElement.prototype.submit.call(form);
4410
+ },
4411
+ 'sitekey': '<?php echo $sitekey; ?>',
4412
+ 'size': 'invisible',
4413
+ 'badge': 'bottomright'
4414
+ });
4415
+
4416
+ form.onsubmit = function (event) {
4417
+ event.preventDefault();
4418
+ grecaptcha.execute(place_id);
4419
+ };
4420
+
4421
+ }
4422
+ </script>
4423
+ <?php
4424
+ }
4425
+ }
4426
+
4427
+ /**
4428
+ * Inline reCAPTCHA widget
4429
+ *
4430
+ */
4431
+ add_action( 'wp_footer', 'cerber_foo', 1000 );
4432
+ function cerber_foo() {
4433
+ global $wp_cerber;
4434
+
4435
+ if (is_singular()) cerber_antibot_code( array( 'botscomm', 'botsany' ) );
4436
+
4437
+ if (!$wp_cerber->recaptcha_here) return;
4438
+
4439
+ // jQuery version with support visible and invisible reCAPTCHA
4440
+ // TODO: convert it into pure JS
4441
+ ?>
4442
+ <script type="text/javascript">
4443
+
4444
+ jQuery(document).ready(function ($) {
4445
+
4446
+ var recaptcha_ok = false;
4447
+ var the_recaptcha_widget = $("#cerber-recaptcha");
4448
+ var is_recaptcha_visible = ($(the_recaptcha_widget).data('size') !== 'invisible');
4449
+
4450
+ var the_form = $(the_recaptcha_widget).closest("form");
4451
+ var the_button = $(the_form).find('input[type="submit"]');
4452
+ if (!the_button.length) {
4453
+ the_button = $(the_form).find(':button');
4454
+ }
4455
+
4456
+ // visible
4457
+ if (the_button.length && is_recaptcha_visible) {
4458
+ the_button.prop("disabled", true);
4459
+ the_button.css("opacity", 0.5);
4460
+ }
4461
+
4462
+ window.form_button_enabler = function () {
4463
+ if (!the_button.length) return;
4464
+ the_button.prop("disabled", false);
4465
+ the_button.css( "opacity", 1 );
4466
+ };
4467
+
4468
+ // invisible
4469
+ if (!is_recaptcha_visible) {
4470
+ $(the_button).click(function (event) {
4471
+ if (recaptcha_ok) return;
4472
+ event.preventDefault();
4473
+ grecaptcha.execute();
4474
+ });
4475
+ }
4476
+
4477
+ window.now_submit_the_form = function () {
4478
+ recaptcha_ok = true;
4479
+ $(the_button).click(); // this is only way to submit a form that contains "submit" inputs
4480
+ };
4481
+ });
4482
+ </script>
4483
+ <script src = "https://www.google.com/recaptcha/api.js?hl=<?php echo cerber_recaptcha_lang(); ?>" async defer></script>
4484
+ <?php
4485
+ }
4486
+
4487
+
4488
+ // Traffic Logging ======================================================================
4489
+
4490
+ //add_action( 'wp', 'cerber_traffic_log' );
4491
+ add_action( 'shutdown', function () {
4492
+ cerber_traffic_log();
4493
+ } );
4494
+ register_shutdown_function( 'cerber_traffic_log' );
4495
+ /**
4496
+ * Traffic Logging
4497
+ *
4498
+ * @since 6.0
4499
+ */
4500
+ function cerber_traffic_log(){
4501
+ global $wpdb, $wp_query, $wp_cerber_user_id, $wp_cerber_start_stamp, $blog_id;
4502
+ static $logged = false;
4503
+
4504
+ if ( $logged ) {
4505
+ return;
4506
+ }
4507
+
4508
+ $wp_cerber = get_wp_cerber();
4509
+
4510
+ $wp_type = 700;
4511
+
4512
+ if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
4513
+ /*
4514
+ if ( isset( $_POST['action'] ) && $_POST['action'] == 'heartbeat' ) {
4515
+ return;
4516
+ }*/
4517
+ $wp_type = 500;
4518
+ }
4519
+ elseif ( is_admin() ) {
4520
+ $wp_type = 501;
4521
+ }
4522
+ elseif ( defined( 'DOING_CRON' ) && DOING_CRON ) {
4523
+ $wp_type = 502;
4524
+ }
4525
+ elseif ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
4526
+ $wp_type = 515;
4527
+ }
4528
+ elseif ( cerber_is_rest_url() ) {
4529
+ $wp_type = 520;
4530
+ }
4531
+ // Public part starts with 600
4532
+ elseif ( $wp_query && is_object( $wp_query ) ) {
4533
+ $wp_type = 600;
4534
+ if ( $wp_query->is_singular ) {
4535
+ $wp_type = 601;
4536
+ }
4537
+ elseif ( $wp_query->is_tag ) {
4538
+ $wp_type = 603;
4539
+ }
4540
+ elseif ( $wp_query->is_category ) {
4541
+ $wp_type = 604;
4542
+ }
4543
+ elseif ( $wp_query->is_search ) {
4544
+ $wp_type = 605;
4545
+ }
4546
+ }
4547
+
4548
+ if ( function_exists( 'http_response_code' ) ) { // PHP >= 5.4.0, PHP 7
4549
+ $http_code = http_response_code();
4550
+ }
4551
+ else {
4552
+ //get_status_header_desc()
4553
+ // TODO: Add detection for other HTTP codes for PHP 5.3
4554
+ $http_code = 200;
4555
+ if ( $wp_type > 600 ) {
4556
+ if ( $wp_query->is_404 ) {
4557
+ $http_code = 404;
4558
+ }
4559
+ }
4560
+ }
4561
+
4562
+ $user_id = 0;
4563
+ if ( function_exists( 'get_current_user_id' ) ) {
4564
+ $user_id = get_current_user_id();
4565
+ }
4566
+ if ( ! $user_id && $wp_cerber_user_id ) {
4567
+ $user_id = absint( $wp_cerber_user_id );
4568
+ }
4569
+
4570
+ if ( ! cerber_to_log( $wp_type, $http_code, $user_id ) ) {
4571
+ return;
4572
+ }
4573
+
4574
+ $logged = true;
4575
+
4576
+ $ua = '';
4577
+ if ( ! empty( $_SERVER['HTTP_USER_AGENT'] ) ) {
4578
+ $ua = substr ($_SERVER['HTTP_USER_AGENT'], 0, 1000);
4579
+ }
4580
+
4581
+ $bot = cerber_is_crawler( $ua );
4582
+ if ( $bot && crb_get_settings( 'tinocrabs' ) ) {
4583
+ return;
4584
+ }
4585
+
4586
+ $ip = $wp_cerber->getRemoteIp();
4587
+ $ip_long = 0;
4588
+ if ( cerber_is_ipv4( $ip ) ) {
4589
+ $ip_long = ip2long( $ip );
4590
+ }
4591
+
4592
+ $wp_id = 0;
4593
+ if ( $wp_query && is_object( $wp_query ) ) {
4594
+ $wp_id = absint( $wp_query->get_queried_object_id() );
4595
+ }
4596
+
4597
+ $session_id = $wp_cerber->getSessionID();
4598
+ if ( is_ssl() ) {
4599
+ $scheme = 'https';
4600
+ }
4601
+ else {
4602
+ $scheme = 'http';
4603
+ }
4604
+ $uri = $scheme . '://'. $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
4605
+ $method = preg_replace( '/[^\w]/', '', $_SERVER['REQUEST_METHOD'] );
4606
+
4607
+ // Request fields
4608
+
4609
+ $fields = '';
4610
+ if ( crb_get_settings( 'tifields' ) ) {
4611
+ $fields = array();
4612
+ if ( ! empty( $_POST ) ) {
4613
+ $fields[1] = cerber_prepare_fields( cerber_mask_fields( (array) $_POST ) );
4614
+ }
4615
+ if ( ! empty( $_GET ) ) {
4616
+ $fields[2] = cerber_prepare_fields( (array) $_GET );
4617
+ }
4618
+ if ( ! empty( $_FILES ) ) {
4619
+ $fields[3] = $_FILES;
4620
+ }
4621
+ if ( ! empty( $fields ) ) {
4622
+ $fields = serialize( $fields );
4623
+ }
4624
+ else {
4625
+ $fields = '';
4626
+ }
4627
+ }
4628
+
4629
+ // Extra request details
4630
+
4631
+ $details = array();
4632
+ if ( $ua ) {
4633
+ $details[1] = $ua;
4634
+ }
4635
+ if ( ! empty( $_SERVER['HTTP_REFERER'] ) ) {
4636
+ //$ref = mb_substr( $_SERVER['HTTP_REFERER'], 0, 1048576 ); // 1 Mb for ASCII
4637
+ $details[2] = filter_var( $_SERVER['HTTP_REFERER'], FILTER_SANITIZE_URL );
4638
+ }
4639
+ /*
4640
+ if ( ! empty( $_FILES ) ) {
4641
+ $details[3] = $_FILES;
4642
+ }*/
4643
+ if ( $wp_type == 605 && ! empty( $_GET['s'] ) ) {
4644
+ $details[4] = $_GET['s'];
4645
+ }
4646
+ if ( $wp_type == 515 ) {
4647
+ // TODO: add a setting to enable it because there is a user/password in the php://input
4648
+ //$details[5] = file_get_contents('php://input');
4649
+ }
4650
+ if ( crb_get_settings( 'tihdrs' ) ) {
4651
+ $hds = getallheaders();
4652
+ unset( $hds['Cookie'] );
4653
+ $details[6] = $hds;
4654
+ }
4655
+ if ( crb_get_settings( 'tisenv' ) ) {
4656
+ $srv = $_SERVER;
4657
+ unset( $srv['HTTP_COOKIE'] );
4658
+ $details[7] = $srv;
4659
+ }
4660
+ if ( crb_get_settings( 'ticandy' ) && ! empty( $_COOKIE ) ) {
4661
+ $details[8] = $_COOKIE;
4662
+ }
4663
+ if ( !empty( $details ) ) {
4664
+ /*
4665
+ foreach ( $details as &$detail ) {
4666
+ $detail = mb_substr($detail, 0, 1048576); // 1 Mb for ASCII
4667
+ }*/
4668
+ $details = cerber_prepare_fields( $details );
4669
+ $details = serialize($details);
4670
+ }
4671
+ else {
4672
+ $details = '';
4673
+ }
4674
+
4675
+ // Timestamps
4676
+ if ( ! empty( $wp_cerber_start_stamp ) && is_numeric( $wp_cerber_start_stamp ) ) {
4677
+ $stamp = (float)$wp_cerber_start_stamp; // define this variable: $wp_cerber_start_stamp = microtime( true ); in wp-config.php
4678
+ }
4679
+ else {
4680
+ $stamp = cerber_request_time();
4681
+ }
4682
+
4683
+ $processing = (int) ( 1000 * ( microtime( true ) - $stamp ) );
4684
+
4685
+ $uri = cerber_real_escape($uri);
4686
+ $fields = cerber_real_escape($fields);
4687
+ $details = cerber_real_escape($details);
4688
+
4689
+ //$uri = $wpdb->remove_placeholder_escape( esc_sql( $uri ) );
4690
+ //$fields = $wpdb->remove_placeholder_escape( esc_sql( $fields ) );
4691
+ //$details = $wpdb->remove_placeholder_escape( esc_sql( $details ) );
4692
+
4693
+ //$query = $wpdb->prepare( 'INSERT INTO ' . CERBER_TRAF_TABLE . ' (ip, ip_long, uri, request_fields , request_details, session_id, user_id, stamp, processing, request_method, http_code, wp_id, wp_type, is_bot, blog_id ) VALUES ("' .$ip .'", '. $ip_long . ', %s, %s, %s, "' . $session_id . '", ' . $user_id . ', ' . $stamp . ',' . $processing . ', "' . $method . '", ' . $http_code . ',' . $wp_id . ', ' . $wp_type . ', ' . $bot . ', ' . absint($blog_id) . ')', $uri, $fields, $details);
4694
+
4695
+ $query = 'INSERT INTO ' . CERBER_TRAF_TABLE . ' (ip, ip_long, uri, request_fields , request_details, session_id, user_id, stamp, processing, request_method, http_code, wp_id, wp_type, is_bot, blog_id ) VALUES ("' . $ip . '", ' . $ip_long . ',"' . $uri . '","' . $fields . '","' . $details . '", "' . $session_id . '", ' . $user_id . ', ' . $stamp . ',' . $processing . ', "' . $method . '", ' . $http_code . ',' . $wp_id . ', ' . $wp_type . ', ' . $bot . ', ' . absint( $blog_id ) . ')';
4696
+
4697
+ //$ret = $wpdb->query( $query );
4698
+
4699
+ $ret = cerber_db_query( $query );
4700
+
4701
+ if (!$ret){
4702
+
4703
+ // mysqli_error($wpdb->dbh);
4704
+
4705
+ // TODO: Daily software error report
4706
+ /*
4707
+ echo mysqli_sqlstate($wpdb->dbh);
4708
+ echo $wpdb->last_error;
4709
+ echo "<p>\n";
4710
+ echo $uri;
4711
+ echo "<p>\n";
4712
+ echo '<p>ERR '.$query.$wpdb->last_error;
4713
+ echo '<p>'.$wpdb->_real_escape( $uri );
4714
+ */
4715
+ }
4716
+
4717
+ }
4718
+
4719
+ /**
4720
+ * To log or not to log current request?
4721
+ *
4722
+ * @param $wp_type integer
4723
+ * @param $http_code integer
4724
+ * @param $user_id integer
4725
+ *
4726
+ * @return bool
4727
+ * @since 6.0
4728
+ */
4729
+ function cerber_to_log($wp_type = 0, $http_code, $user_id){
4730
+ global $cerber_logged;
4731
+
4732
+ $mode = crb_get_settings( 'timode' );
4733
+
4734
+ if ($mode == 0) {
4735
+ return false;
4736
+ }
4737
+ if ($mode == 2) {
4738
+ if ($wp_type < 515) { // Pure admin requests
4739
+ if ( $wp_type < 502 && ! $user_id ) { // @since 6.3
4740
+ return true;
4741
+ }
4742
+ return false;
4743
+ }
4744
+ return true;
4745
+ }
4746
+
4747
+ // Smart mode ---------------------------------------------------------
4748
+
4749
+ if ( ! empty( $cerber_logged ) ) {
4750
+ $tmp = $cerber_logged;
4751
+ unset( $tmp[7] );
4752
+ unset( $tmp[51] );
4753
+ if ( ! empty( $tmp ) ) {
4754
+ return true;
4755
+ }
4756
+ }
4757
+
4758
+ if ($wp_type < 515) {
4759
+ if ( $wp_type < 502 && ! $user_id ) { // @since 6.3
4760
+ return true;
4761
+ }
4762
+ return false;
4763
+ }
4764
+
4765
+ if ( $http_code >= 400 ||
4766
+ $wp_type < 600 ||
4767
+ $user_id ||
4768
+ cerber_is_http_post() ||
4769
+ isset($_GET['s']) ||
4770
+ cerber_get_non_wp_fields()){
4771
+ return true;
4772
+ }
4773
+
4774
+ if ( cerber_get_uri_script() ) {
4775
+ return true;
4776
+ }
4777
+
4778
+ return false;
4779
+ }
4780
+
4781
+ /**
4782
+ * Mask sensitive request fields before saving in DB (avoid information leaks)
4783
+ *
4784
+ * @param $fields array
4785
+ *
4786
+ * @return array
4787
+ * @since 6.0
4788
+ */
4789
+ function cerber_mask_fields( $fields ) {
4790
+ $to_mask = array( 'pwd', 'pass', 'password' );
4791
+ if ($list = (array)crb_get_settings( 'timask' )){
4792
+ $to_mask = array_merge($to_mask, $list);
4793
+ }
4794
+ foreach ( $to_mask as $mask_field ) {
4795
+ if ( ! empty( $fields[ $mask_field ] ) ) {
4796
+ $fields[ $mask_field ] = str_pad( '', mb_strlen( $fields[ $mask_field ] ), '*' );
4797
+ }
4798
+ }
4799
+
4800
+ return $fields;
4801
+ }
4802
+
4803
+ /**
4804
+ * Recursive prepare values in array for inserting into DB
4805
+ *
4806
+ * @param $list
4807
+ *
4808
+ * @return mixed
4809
+ * @since 6.0
4810
+ */
4811
+ function cerber_prepare_fields( $list ) {
4812
+ foreach ( $list as &$field ) {
4813
+ if ( is_array( $field ) ) {
4814
+ cerber_prepare_fields( @$field );
4815
+ /*
4816
+ foreach ( $field as &$field_2 ) {
4817
+ $field_2 = mb_substr( $field_2, 0, 1048576 ); // 1 Mb for ASCII
4818
+ }*/
4819
+ }
4820
+ else {
4821
+ if ( ! $field ) {
4822
+ $field = '';
4823
+ }
4824
+ $field = mb_substr( $field, 0, 1048576 ); // 1 Mb for ASCII
4825
+ }
4826
+ }
4827
+
4828
+ $list = stripslashes_deep( $list );
4829
+
4830
+ return $list;
4831
+ }
4832
+
4833
+ /**
4834
+ * Request time
4835
+ *
4836
+ * @return mixed
4837
+ * @since 6.0
4838
+ */
4839
+ function cerber_request_time() {
4840
+ static $stamp;
4841
+
4842
+ if ( ! isset( $stamp ) ) {
4843
+ if ( ! empty( $_SERVER['REQUEST_TIME_FLOAT'] ) ) { // PHP >= 5.4
4844
+ $stamp = $_SERVER['REQUEST_TIME_FLOAT'];
4845
+ $stamp = filter_var( $_SERVER['REQUEST_TIME_FLOAT'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION );
4846
+ }
4847
+ else {
4848
+ $stamp = microtime( true );
4849
+ }
4850
+ }
4851
+
4852
+ return $stamp;
4853
+ }
4854
+
4855
+ /**
4856
+ * Return non WP public query fields
4857
+ *
4858
+ * @param array $fields An associative array field => value to check
4859
+ *
4860
+ * @return array
4861
+ * @since 6.0
4862
+ */
4863
+ function cerber_get_non_wp_fields($fields = array()) {
4864
+ global $wp_query;
4865
+
4866
+ if ( empty( $fields ) ) {
4867
+ $get_keys = array_keys( $_GET );
4868
+ }
4869
+ else {
4870
+ $get_keys = array_keys( $fields );
4871
+ }
4872
+
4873
+ if ( empty( $get_keys ) ) {
4874
+ return array();
4875
+ }
4876
+
4877
+ if ( is_object($wp_query) ) {
4878
+ $keys = $wp_query->fill_query_vars( array() );
4879
+ }
4880
+ else {
4881
+ $tmp = new WP_Query();
4882
+ $keys = $tmp->fill_query_vars( array() );
4883
+ }
4884
+
4885
+ $wp_keys = array_keys( $keys ); // WordPress GET fields for frontend
4886
+
4887
+ $wp_keys[] = 'redirect_to';
4888
+ $wp_keys[] = 'reauth';
4889
+ $wp_keys[] = 'action';
4890
+ $wp_keys[] = '_wpnonce';
4891
+ $wp_keys[] = 'loggedout';
4892
+
4893
+ // WP Customizer fields
4894
+ $wp_keys = array_merge($wp_keys, array( 'nonce', '_method', 'wp_customize', 'changeset_uuid', 'customize_changeset_uuid', 'customize_theme', 'theme', 'customize_messenger_channel', 'customize_autosaved' ));
4895
+
4896
+ $ret = array_diff( $get_keys, $wp_keys );
4897
+
4898
+ if ( ! $ret ) {
4899
+ $ret = array();
4900
+ }
4901
+
4902
+ return $ret;
4903
+
4904
+ }
4905
+
4906
+
4907
+ /**
4908
+ *
4909
+ * @since 6.0
4910
+ */
4911
+ function cerber_beast(){
4912
+ global $cerber_status;
4913
+
4914
+ if ( is_admin()
4915
+ || ( defined( 'DOING_CRON' ) && DOING_CRON )
4916
+ || ( defined( 'WP_CLI' ) && WP_CLI )
4917
+ ) {
4918
+ return;
4919
+ }
4920
+
4921
+ $wp_cerber = get_wp_cerber();
4922
+
4923
+ $wp_cerber->CheckProhibitedURI();
4924
+
4925
+ if ( !crb_get_settings( 'tienabled' ) ) {
4926
+ return;
4927
+ }
4928
+
4929
+ $uri = cerber_purify_uri();
4930
+
4931
+ if ( $tiwhite = crb_get_settings( 'tiwhite' ) ) {
4932
+ foreach ( (array)$tiwhite as $item ) {
4933
+ if ($item == $uri){
4934
+ return;
4935
+ }
4936
+ }
4937
+ }
4938
+
4939
+ $wp_cerber->InspectRequest();
4940
+
4941
+ $uri_script = cerber_get_uri_script();
4942
+
4943
+ if ( $uri_script && $script_filename = cerber_script_filename() ) {
4944
+ // Scaning for executable scripts?
4945
+ //if ( false === strrpos( $script_filename, $uri ) ) {
4946
+ if ( !cerber_script_exists( $uri ) ) {
4947
+ $wp_cerber = get_wp_cerber();
4948
+ $cerber_status = 13;
4949
+ cerber_log( 55 );
4950
+ cerber_soft_block_add( $wp_cerber->getRemoteIp(), 8);
4951
+ //cerber_404_page( true );
4952
+ cerber_forbidden_page();
4953
+ }
4954
+ // Direct access to a PHP script
4955
+ if ( ! in_array( $uri_script, cerber_get_wp_scripts() ) ) {
4956
+ $deny = false;
4957
+ if ( cerber_acl_check() == 'B' ) {
4958
+ $deny = true;
4959
+ $cerber_status = 14;
4960
+ }
4961
+ elseif (!cerber_is_allowed() ) {
4962
+ $deny = true;
4963
+ $cerber_status = 13;
4964
+ }
4965
+ elseif ( lab_is_blocked( null, true ) ) {
4966
+ $deny = true;
4967
+ $cerber_status = 15;
4968
+ }
4969
+ if ($deny){
4970
+ cerber_log( 50 );
4971
+ //cerber_404_page( true );
4972
+ cerber_forbidden_page();
4973
+ }
4974
+ }
4975
+ }
4976
+ }
cerber-news.php CHANGED
@@ -129,6 +129,12 @@ function cerber_push_the_news( $version ) {
129
  $news['6.2'][] = 'Bug fixed: If the WP REST API is blocked, a request with specially malformed URL can bypass protection. Thanks to Tomasz Wasiak.';
130
  $news['6.2'][] = 'Bug fixed: An IPv4 range in the Access Lists might not work as expected, depending on server/site settings.';
131
 
 
 
 
 
 
 
132
 
133
  if ( ! empty( $news[ $version ] ) ) {
134
  //$text = '<h3>What\'s new in WP Cerber '.$version.'</h3>';
@@ -150,7 +156,7 @@ function cerber_push_the_news( $version ) {
150
 
151
  function cerber_admin_info($msg, $type = 'normal'){
152
 
153
- $crb_assets_url = plugin_dir_url( CERBER_FILE ) . 'assets/';
154
 
155
  update_site_option('cerber_admin_info',
156
  '<table><tr><td><img style="float:left; margin-left:-10px;" src="'.$crb_assets_url.'icon-128x128.png"></td>'.
129
  $news['6.2'][] = 'Bug fixed: If the WP REST API is blocked, a request with specially malformed URL can bypass protection. Thanks to Tomasz Wasiak.';
130
  $news['6.2'][] = 'Bug fixed: An IPv4 range in the Access Lists might not work as expected, depending on server/site settings.';
131
 
132
+ $news['6.5'][] = 'This version brings a new, advanced and more effective way of loading plugin modules and the plugin security engine. This allows Cerber Security to intercept and inspect suspicious requests more effectively and protect WordPress against attacks that try to exploit a vulnerability in a plugin or a theme. It’s advised to enable loading in Standard mode. To enable this new mode go to the Main Settings plugin admin page and set the Load security engine setting to Standard mode.';
133
+ $news['6.5'][] = 'Traffic Inspector’s algorithms detect and deny any attempt to upload executable files (including PHP and JavaScript) or .htaccess file via any public form or POST request.';
134
+ $news['6.5'][] = 'A new setting to disable email notifications about new versions of the plugin. It’s located on the Notification admin page in the Email notifications section.';
135
+ $news['6.5'][] = 'Search in the traffic log. Now it’s possible to search in the User agent string and filter out the HTTP method (GET/POST).';
136
+ $news['6.5'][] = 'In the Smart mode if a user is not logged in, all requests to the admin dashboard are logged.';
137
+ $news['6.5'][] = 'Performance of the logging subsystem is improved: the DB query has been updated.';
138
 
139
  if ( ! empty( $news[ $version ] ) ) {
140
  //$text = '<h3>What\'s new in WP Cerber '.$version.'</h3>';
156
 
157
  function cerber_admin_info($msg, $type = 'normal'){
158
 
159
+ $crb_assets_url = cerber_plugin_dir_url() . 'assets/';
160
 
161
  update_site_option('cerber_admin_info',
162
  '<table><tr><td><img style="float:left; margin-left:-10px;" src="'.$crb_assets_url.'icon-128x128.png"></td>'.
cerber-tools.php CHANGED
@@ -35,7 +35,7 @@
35
  */
36
  function cerber_tools_page() {
37
 
38
- $tab = cerber_get_tab( 'imex', array( 'imex', 'diagnostic', 'license' ) );
39
 
40
  ?>
41
  <div class="wrap">
@@ -45,9 +45,10 @@ function cerber_tools_page() {
45
  <h2 class="nav-tab-wrapper cerber-tabs">
46
  <?php
47
 
48
- echo '<a href="' . cerber_admin_link('imex') . '" class="nav-tab ' . ( $tab == 'imex' ? 'nav-tab-active' : '') . '"><span class="dashicons dashicons-admin-generic"></span> ' . __('Export & Import') . '</a>';
49
- echo '<a href="' . cerber_admin_link('diagnostic') . '" class="nav-tab ' . ( $tab == 'diagnostic' ? 'nav-tab-active' : '') . '"><span class="dashicons dashicons-admin-tools"></span> ' . __('Diagnostic') . '</a>';
50
- echo '<a href="' . cerber_admin_link('license') . '" class="nav-tab ' . ( $tab == 'license' ? 'nav-tab-active' : '') . '"><span class="dashicons dashicons-id-alt"></span> ' . __('License') . '</a>';
 
51
 
52
  echo lab_indicator();
53
  ?>
@@ -66,6 +67,9 @@ function cerber_tools_page() {
66
  case 'license':
67
  cerber_show_lic();
68
  break;
 
 
 
69
  default: cerber_show_imex();
70
  }
71
 
@@ -202,13 +206,13 @@ function cerber_show_diag(){
202
  }
203
  if ($issues) {
204
  $issues = '<p>'.implode('</p><p>',$issues).'</p>';
205
- $sections[] = array('<h3>Non-critical issues found</h3>',$issues);
206
  }
207
  ?>
208
  <!-- <h3 style="margin-top: 3em;">Diagnostic and maintenance</h3>
209
  <a href="javascript:void(0)" onclick="toggle_visibility('diagnostic'); return false;">Show diagnostic information</a>
210
  -->
211
- <form id="diagnostic" style="margin-top: 2em;">
212
  <?php
213
  foreach ($sections as $section){
214
  echo '<div class="diag-section">';
@@ -219,7 +223,7 @@ function cerber_show_diag(){
219
  ?>
220
  <div class="diag-section">
221
  <h3>WordPress info</h3>
222
- <div class="diag-text"><?php echo cerber_wp_diag(); ?></div>
223
  </div>
224
  <div class="diag-section">
225
  <h3>Database info</h3>
@@ -228,7 +232,7 @@ function cerber_show_diag(){
228
  </div>
229
  <div class="diag-section">
230
  <h3>Server info</h3>
231
- <textarea name="dia"><?php
232
  echo 'PHP version: ' . phpversion() . "\n";
233
  $server = $_SERVER;
234
  unset($server['HTTP_COOKIE']);
@@ -242,8 +246,11 @@ function cerber_show_diag(){
242
  <h3>Cerber Cloud status</h3>
243
  <?php
244
  echo lab_status();
245
- echo '<p style="text-align: right;"><a class="button button-secondary" href="'.wp_nonce_url(add_query_arg(array('force_check_nodes'=>1)),'control','cerber_nonce').'">Force recheck nodes</a></p>';
246
  ?>
 
 
 
 
247
  </div>
248
  <?php
249
  if ( $report = get_site_option( '_cerber_report' ) ) {
@@ -342,4 +349,67 @@ function cerber_recaptcha_page() {
342
  ?>
343
  </div>
344
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
345
  }
35
  */
36
  function cerber_tools_page() {
37
 
38
+ $tab = cerber_get_tab( 'imex', array( 'imex', 'diagnostic', 'license', 'help' ) );
39
 
40
  ?>
41
  <div class="wrap">
45
  <h2 class="nav-tab-wrapper cerber-tabs">
46
  <?php
47
 
48
+ echo '<a href="' . cerber_admin_link( 'imex' ) . '" class="nav-tab ' . ( $tab == 'imex' ? 'nav-tab-active' : '' ) . '"><span class="dashicons dashicons-admin-generic"></span> ' . __( 'Export & Import' ) . '</a>';
49
+ echo '<a href="' . cerber_admin_link( 'diagnostic' ) . '" class="nav-tab ' . ( $tab == 'diagnostic' ? 'nav-tab-active' : '' ) . '"><span class="dashicons dashicons-admin-tools"></span> ' . __( 'Diagnostic' ) . '</a>';
50
+ echo '<a href="' . cerber_admin_link( 'license' ) . '" class="nav-tab ' . ( $tab == 'license' ? 'nav-tab-active' : '' ) . '"><span class="dashicons dashicons-id-alt"></span> ' . __( 'License' ) . '</a>';
51
+ echo '<a href="' . cerber_admin_link('help',array('page'=>cerber_get_admin_page())) . '" class="nav-tab ' . ( $tab == 'help' ? 'nav-tab-active' : '') . '"><span class="dashicons dashicons-editor-help"></span> ' . __('Help','wp-cerber') . '</a>';
52
 
53
  echo lab_indicator();
54
  ?>
67
  case 'license':
68
  cerber_show_lic();
69
  break;
70
+ case 'help':
71
+ cerber_show_help();
72
+ break;
73
  default: cerber_show_imex();
74
  }
75
 
206
  }
207
  if ($issues) {
208
  $issues = '<p>'.implode('</p><p>',$issues).'</p>';
209
+ $sections[] = array('<h3><span class="dashicons dashicons-warning"></span> Non-critical issues found</h3>',$issues);
210
  }
211
  ?>
212
  <!-- <h3 style="margin-top: 3em;">Diagnostic and maintenance</h3>
213
  <a href="javascript:void(0)" onclick="toggle_visibility('diagnostic'); return false;">Show diagnostic information</a>
214
  -->
215
+ <form id="diagnostic">
216
  <?php
217
  foreach ($sections as $section){
218
  echo '<div class="diag-section">';
223
  ?>
224
  <div class="diag-section">
225
  <h3>WordPress info</h3>
226
+ <div class="diag-text"><?php cerber_show_wp_diag(); ?></div>
227
  </div>
228
  <div class="diag-section">
229
  <h3>Database info</h3>
232
  </div>
233
  <div class="diag-section">
234
  <h3>Server info</h3>
235
+ <textarea name="dia" class="code"><?php
236
  echo 'PHP version: ' . phpversion() . "\n";
237
  $server = $_SERVER;
238
  unset($server['HTTP_COOKIE']);
246
  <h3>Cerber Cloud status</h3>
247
  <?php
248
  echo lab_status();
 
249
  ?>
250
+ <p style="text-align: right;">
251
+ <a class="button button-secondary" href="<?php echo wp_nonce_url( add_query_arg( array( 'clean_up_the_cache' => 1 ) ), 'control', 'cerber_nonce' ); ?>">Clean up the cache</a>
252
+ <a class="button button-secondary" href="<?php echo wp_nonce_url( add_query_arg( array( 'force_check_nodes' => 1 ) ), 'control', 'cerber_nonce' ); ?>">Force recheck nodes</a>
253
+ </p>
254
  </div>
255
  <?php
256
  if ( $report = get_site_option( '_cerber_report' ) ) {
349
  ?>
350
  </div>
351
  <?php
352
+ }
353
+
354
+ function cerber_show_wp_diag(){
355
+ global $wp_version, $wpdb;
356
+
357
+ $ret = array();
358
+
359
+ $ret[] = cerber_make_plain_table( array(
360
+ array('WordPress version', $wp_version),
361
+ array('Options DB table', $wpdb->prefix.'options'),
362
+ array('Server platform', PHP_OS),
363
+ ) );
364
+
365
+ $uploads = wp_upload_dir();
366
+
367
+ $folders = array(
368
+ array( 'WordPress root folder (ABSPATH) ', ABSPATH ),
369
+ array( 'Uploads folder', $uploads['path'] ),
370
+ array( 'Content folder (WP_CONTENT_DIR) ', WP_CONTENT_DIR ),
371
+ array( 'Plugins folder (WP_PLUGIN_DIR) ', WP_PLUGIN_DIR ),
372
+ array( 'Must use plugin folder (WPMU_PLUGIN_DIR) ', WPMU_PLUGIN_DIR ),
373
+ );
374
+
375
+ foreach ( $folders as &$folder ) {
376
+ $folder[2] = '';
377
+ $folder[3] = '';
378
+ if ( file_exists( $folder[1] ) ) {
379
+ if ( wp_is_writable( $folder[1] ) ) {
380
+ $folder[2] = 'Writable';
381
+ }
382
+ $folder[3] = cerber_get_chmod($folder[1]);
383
+ }
384
+ else {
385
+ $folder[2] = 'Not found';
386
+ }
387
+ }
388
+
389
+ $ret[] = '<p>Folders</p>'.cerber_make_plain_table( $folders );
390
+
391
+ $pls = array();
392
+ $list = get_option('active_plugins');
393
+ foreach($list as $plugin) {
394
+ $data = get_plugin_data(WP_PLUGIN_DIR.'/'.$plugin);
395
+ $pls[] = array($data['Name'], $data['Version']);
396
+ }
397
+
398
+ $ret[] = 'Active plugins<br>'.cerber_make_plain_table( $pls );
399
+
400
+ echo implode("<br>",$ret);
401
+ }
402
+
403
+ function cerber_make_plain_table( $data ) {
404
+ $ret = '<table class="crb-plain-table">';
405
+ foreach ( $data as $row ) {
406
+ $ret .= '<tr><td>' . implode( '</td><td>', $row ) . '</td></tr>';
407
+ }
408
+ $ret .= '</table>';
409
+
410
+ return $ret;
411
+ }
412
+
413
+ function cerber_get_chmod( $file ) {
414
+ return substr( sprintf( '%o', @fileperms( $file ) ), - 4 );
415
  }
common.php CHANGED
@@ -54,20 +54,28 @@ function cerber_get_wp_scripts(){
54
  function cerber_admin_link($tab = '', $args = array()){
55
  //return add_query_arg(array('record_id'=>$record_id,'mode'=>'view_record'),admin_url('admin.php?page=storage'));
56
 
57
- if ( in_array( $tab, array( 'recaptcha', 'antispam' ) ) ) {
58
- $page = 'cerber-recaptcha';
59
- $tab = null;
60
- }
61
- elseif ( in_array( $tab, array( 'imex', 'diagnostic', 'license' ) ) ) {
62
- $page = 'cerber-tools';
63
- }
64
- elseif ( in_array( $tab, array( 'traffic', 'ti_settings' ) ) ) {
65
- $page = 'cerber-traffic';
 
 
 
 
 
 
 
 
66
  }
67
- elseif ( in_array( $tab, array( 'geo' ) ) ) {
68
- $page = 'cerber-rules';
 
69
  }
70
- else $page = 'cerber-security';
71
 
72
  if (!is_multisite()) {
73
  $link = admin_url('admin.php?page='.$page);
@@ -247,13 +255,18 @@ function cerber_check_environment(){
247
  if ( '' === crb_get_settings( 'tienabled' ) ) {
248
  cerber_admin_notice('Warning: Traffic inspection is disabled');
249
  }
250
- if (!in_array('curl', get_loaded_extensions())) {
251
- cerber_admin_notice( __( 'ERROR:', 'wp-cerber' ) . ' cURL PHP library is not enabled on your website.');
252
  }
253
  else {
254
  $curl = @curl_init();
255
- if (!$curl && ($err_msg = curl_error($curl))) cerber_admin_notice( __( 'ERROR:', 'wp-cerber' ) .' '. $err_msg);
256
- curl_close($curl);
 
 
 
 
 
257
  }
258
  }
259
 
@@ -480,7 +493,7 @@ function cerber_is_rest_url(){
480
  return true;
481
  }
482
 
483
- if (isset($cache)) {
484
  return $cache;
485
  }
486
 
@@ -623,37 +636,67 @@ function cerber_last_uri( $check_php = false ) {
623
  }
624
 
625
  /**
626
- * Return the name of a PHP script in the requested URI if it's present
627
  *
628
- * @return bool|string
629
  */
630
- function cerber_get_uri_script(){
631
- static $executable = array( 'phtm', 'phtml', 'phps', 'asp', 'aspx', 'shtm', 'shtml' );
632
-
633
  $last = cerber_last_uri();
634
- //$ext = substr( strrchr( $last, '.' ), 1 );
635
- // Get real extension for any set of additional fake extensions (aka double extensions)
636
- $ext = substr( strstr( $last, '.' ), 1 );
637
- if ( $second_dot = strpos( $ext, '.' ) ) {
638
- $ext = substr( $ext, 0, $second_dot );
639
  }
640
 
641
- if ( ! $ext ) {
642
- return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
643
  }
644
 
645
- $ext = strtolower( $ext );
 
646
 
647
- if ( $ext == 'php' ) {
648
- return $last;
649
  }
650
 
651
- if ( in_array($ext, $executable) ) {
652
- return $last;
 
 
 
 
 
 
 
 
 
 
 
 
 
653
  }
654
 
655
- if ( preg_match( '/php\d+/', $ext ) ) {
656
- return $last;
 
 
 
 
 
 
657
  }
658
 
659
  return false;
@@ -692,6 +735,23 @@ function cerber_script_filename() {
692
  return preg_replace('/[\/\\\\]+/','/',$_SERVER['SCRIPT_FILENAME']); // Windows server
693
  }
694
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
695
  /*
696
  * Sets of human readable labels for vary activity/logs events
697
  * @since 1.0
@@ -741,6 +801,8 @@ function cerber_get_labels($type = 'activity'){
741
  $labels[53]=__('Attempt to log in denied','wp-cerber');
742
  $labels[54]=__('Attempt to register denied','wp-cerber');
743
  $labels[55]=__('Probing for vulnerable PHP code','wp-cerber');
 
 
744
 
745
  $labels[70]=__('Request to REST API denied','wp-cerber');
746
  $labels[71]=__('XML-RPC request denied','wp-cerber');
@@ -765,11 +827,11 @@ function cerber_get_labels($type = 'activity'){
765
  function crb_get_activity_set($slice = 'malicious') {
766
  switch ( $slice ) {
767
  case 'malicious':
768
- return array( 10, 11, 16, 17, 40, 50, 51, 52, 53, 54, 55 );
769
  case 'suspicious':
770
- return array( 10, 11, 16, 17, 20, 40, 50, 51, 52, 53, 54, 55 );
771
  case 'black':
772
- return array( 16, 17, 40, 50, 51, 52, 55 );
773
  }
774
 
775
  return array();
@@ -1120,31 +1182,36 @@ function cerber_real_escape($string){
1120
  }
1121
 
1122
  /**
1123
- * Direct SQL query to the DB
1124
  *
1125
  * The reason: https://make.wordpress.org/core/2017/10/31/changed-behaviour-of-esc_sql-in-wordpress-4-8-3/
1126
  *
1127
- * @param $query
1128
  *
1129
- * @return bool|mysqli_result|resource
1130
  * @since 6.0
1131
  */
1132
- function cerber_direct_db_query( $query ) {
1133
  global $wpdb;
1134
- // Check for connected DB handler
1135
- if ( ! is_object( $wpdb ) || empty( $wpdb->dbh ) ) {
1136
- if ( ! $db = cerber_direct_db_connect() ) {
1137
- return false;
 
 
 
 
 
 
 
1138
  }
1139
  }
1140
- else {
1141
- $db = $wpdb;
1142
- }
1143
  if ( $db->use_mysqli ) {
1144
  $ret = mysqli_query( $db->dbh, $query );
1145
  }
1146
  else {
1147
- $ret = mysql_query( $query, $db->dbh );
1148
  }
1149
 
1150
  return $ret;
@@ -1155,33 +1222,39 @@ function cerber_direct_db_query( $query ) {
1155
  *
1156
  * @return bool|wpdb
1157
  */
1158
- function cerber_direct_db_connect(){
1159
  if ( ! defined( 'CRB_ABSPATH' ) ) {
1160
  define( 'CRB_ABSPATH', dirname( __FILE__, 4 ) );
1161
  }
1162
- $db_class = CRB_ABSPATH . '/wp-includes/wp-db.php';
1163
  $wp_config = CRB_ABSPATH . '/wp-config.php';
1164
- if ( file_exists( $db_class ) && $config = @file( $wp_config ) ) {
1165
- $list = array();
1166
- foreach ( $config as $line ) {
1167
- if ( false !== strpos( $line, 'define' ) ) {
1168
- $list[] = $line;
1169
- }
1170
- }
1171
- if ($list) {
1172
- ob_start();
1173
- @eval( implode( ' ', $list ) ); // TODO: replace with REGEX extracting
1174
- ob_end_clean();
1175
- if ( defined( 'DB_USER' ) && defined( 'DB_PASSWORD' ) && defined( 'DB_NAME' ) && defined( 'DB_HOST' ) ) {
1176
- include_once( $db_class );
1177
- return new wpdb( DB_USER, DB_PASSWORD, DB_NAME, DB_HOST );
1178
- }
1179
  }
1180
  }
1181
 
1182
  return false;
1183
  }
1184
 
 
 
 
 
 
 
 
 
 
 
 
1185
  /**
1186
  * Set Cerber Groove to logged in user browser
1187
  *
@@ -1233,6 +1306,8 @@ function cerber_check_groove( $hash = '' ) {
1233
  Get the special public Cerber Sign for using with cookies
1234
  */
1235
  function cerber_get_groove_x( $regenerate = false ) {
 
 
1236
  if ( ! $regenerate ) {
1237
  $groove_x = cerber_get_site_option( 'cerber-groove-x' );
1238
  }
@@ -1281,8 +1356,15 @@ function cerber_htaccess_sync( $settings = array() ) {
1281
  }
1282
 
1283
  // Update all rules in a section - adding/deleting
1284
- //return insert_with_markers( $htaccess_file, 'WP CERBER GROOVE', $rules );
1285
- return cerber_update_htaccess( 'WP CERBER GROOVE', $rules );
 
 
 
 
 
 
 
1286
  }
1287
 
1288
  /**
@@ -1297,15 +1379,15 @@ function cerber_update_htaccess($marker, $rules = array()){
1297
  if ( ! $marker ) {
1298
  return false;
1299
  }
1300
- if ( ! $htaccess_file = cerber_get_htaccess() ) {
1301
  return 'ERROR: Unable to modify the .htaccess file';
1302
  }
1303
  require_once( ABSPATH . 'wp-admin/includes/misc.php' );
1304
- if ( ! got_mod_rewrite() ) {
1305
  return 'ERROR: Apache mod_rewrite is not enabled';
1306
  }
1307
 
1308
- $result = insert_with_markers( $htaccess_file, 'WP CERBER GROOVE', $rules );
1309
 
1310
  if ( $result || $result === 0 ) {
1311
  $result = true;
@@ -1317,14 +1399,84 @@ function cerber_update_htaccess($marker, $rules = array()){
1317
  return $result;
1318
  }
1319
 
1320
- function cerber_get_htaccess() {
 
 
 
 
 
1321
  require_once( ABSPATH . 'wp-admin/includes/file.php' );
1322
  $home_path = get_home_path();
1323
- $htaccess = $home_path . '.htaccess';
1324
- if ( ! is_writable( $htaccess ) ) {
1325
  // should we create the file?
1326
  return false;
1327
  }
1328
 
1329
- return $htaccess;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1330
  }
54
  function cerber_admin_link($tab = '', $args = array()){
55
  //return add_query_arg(array('record_id'=>$record_id,'mode'=>'view_record'),admin_url('admin.php?page=storage'));
56
 
57
+ if (empty($args['page'])) {
58
+ if ( in_array( $tab, array( 'recaptcha', 'antispam' ) ) ) {
59
+ $page = 'cerber-recaptcha';
60
+ $tab = null;
61
+ }
62
+ elseif ( in_array( $tab, array( 'imex', 'diagnostic', 'license' ) ) ) {
63
+ $page = 'cerber-tools';
64
+ }
65
+ elseif ( in_array( $tab, array( 'traffic', 'ti_settings' ) ) ) {
66
+ $page = 'cerber-traffic';
67
+ }
68
+ elseif ( in_array( $tab, array( 'geo' ) ) ) {
69
+ $page = 'cerber-rules';
70
+ }
71
+ else {
72
+ $page = 'cerber-security';
73
+ }
74
  }
75
+ else {
76
+ $page = $args['page'];
77
+ unset( $args['page'] );
78
  }
 
79
 
80
  if (!is_multisite()) {
81
  $link = admin_url('admin.php?page='.$page);
255
  if ( '' === crb_get_settings( 'tienabled' ) ) {
256
  cerber_admin_notice('Warning: Traffic inspection is disabled');
257
  }
258
+ if ( ! in_array( 'curl', get_loaded_extensions() ) ) {
259
+ cerber_admin_notice( __( 'ERROR:', 'wp-cerber' ) . ' cURL PHP library is not enabled on your website.' );
260
  }
261
  else {
262
  $curl = @curl_init();
263
+ if ( ! $curl && ( $err_msg = curl_error( $curl ) ) ) {
264
+ cerber_admin_notice( __( 'ERROR:', 'wp-cerber' ) . ' ' . $err_msg );
265
+ }
266
+ curl_close( $curl );
267
+ }
268
+ if ( cerber_get_mode() != crb_get_settings( 'boot-mode' ) ) {
269
+ cerber_admin_notice( __( 'ERROR:', 'wp-cerber' ) . ' ' . 'The plugin is initialized in a different mode that does not match the settings.' );
270
  }
271
  }
272
 
493
  return true;
494
  }
495
 
496
+ if ( isset( $cache ) ) {
497
  return $cache;
498
  }
499
 
636
  }
637
 
638
  /**
639
+ * Return the name of an executable script in the requested URI if it's present
640
  *
641
+ * @return bool|string script name or false if executable script is not detected
642
  */
643
+ function cerber_get_uri_script() {
 
 
644
  $last = cerber_last_uri();
645
+ if ( cerber_detect_exec_extension( $last ) ) {
646
+ return $last;
 
 
 
647
  }
648
 
649
+ return false;
650
+ }
651
+
652
+ /**
653
+ * Detects an executable extension in a filename.
654
+ * Supports double and N fake extensions.
655
+ *
656
+ * @param $line string Filename
657
+ * @param array $extra A list of additional extensions to detect
658
+ *
659
+ * @return bool|string An extension if it's found, false otherwise
660
+ */
661
+ function cerber_detect_exec_extension( $line, $extra = array() ) {
662
+ $executable = array( 'php', 'phtm', 'phtml', 'phps', 'shtm', 'shtml', 'jsp', 'asp', 'aspx', 'exe', 'com', 'cgi', 'pl' );
663
+
664
+ if ( $extra ) {
665
+ $executable = array_merge( $executable, $extra );
666
  }
667
 
668
+ $line = trim( $line );
669
+ $line = trim( $line, '/' );
670
 
671
+ if ( ! strrpos( $line, '.' ) ) {
672
+ return false;
673
  }
674
 
675
+ $parts = explode('.', $line);
676
+ array_shift($parts);
677
+
678
+ // First and last are critical for most server environments
679
+ $first_ext = array_shift($parts);
680
+ $last_ext = array_pop($parts);
681
+
682
+ if ( $first_ext ) {
683
+ $first_ext = strtolower( $first_ext );
684
+ if ( in_array( $first_ext, $executable ) ) {
685
+ return $first_ext;
686
+ }
687
+ if ( preg_match( '/php\d+/', $first_ext ) ) {
688
+ return $first_ext;
689
+ }
690
  }
691
 
692
+ if ( $last_ext ) {
693
+ $last_ext = strtolower( $last_ext );
694
+ if ( in_array( $last_ext, $executable ) ) {
695
+ return $last_ext;
696
+ }
697
+ if ( preg_match( '/php\d+/', $last_ext ) ) {
698
+ return $last_ext;
699
+ }
700
  }
701
 
702
  return false;
735
  return preg_replace('/[\/\\\\]+/','/',$_SERVER['SCRIPT_FILENAME']); // Windows server
736
  }
737
 
738
+ function cerber_script_exists( $uri ) {
739
+ $script_filename = cerber_script_filename();
740
+ if ( is_multisite() && ! is_subdomain_install() ) {
741
+ $path = explode( '/', $uri );
742
+ if ( count( $path ) > 1 ) {
743
+ $last = array_pop( $path );
744
+ $virtual_sub_folder = array_pop( $path );
745
+ $uri = implode( '/', $path ) . '/' . $last;
746
+ }
747
+ }
748
+ if ( false === strrpos( $script_filename, $uri ) ) {
749
+ return false;
750
+ }
751
+
752
+ return true;
753
+ }
754
+
755
  /*
756
  * Sets of human readable labels for vary activity/logs events
757
  * @since 1.0
801
  $labels[53]=__('Attempt to log in denied','wp-cerber');
802
  $labels[54]=__('Attempt to register denied','wp-cerber');
803
  $labels[55]=__('Probing for vulnerable PHP code','wp-cerber');
804
+ $labels[56]=__('Attempt to upload executable file denied', 'wp-cerber' );
805
+ $labels[57]=__('File upload denied', 'wp-cerber' );
806
 
807
  $labels[70]=__('Request to REST API denied','wp-cerber');
808
  $labels[71]=__('XML-RPC request denied','wp-cerber');
827
  function crb_get_activity_set($slice = 'malicious') {
828
  switch ( $slice ) {
829
  case 'malicious':
830
+ return array( 10, 11, 16, 17, 40, 50, 51, 52, 53, 54, 55, 56 );
831
  case 'suspicious':
832
+ return array( 10, 11, 16, 17, 20, 40, 50, 51, 52, 53, 54, 55, 56, 70, 71);
833
  case 'black':
834
+ return array( 16, 17, 40, 50, 51, 52, 55, 56 );
835
  }
836
 
837
  return array();
1182
  }
1183
 
1184
  /**
1185
+ * Performs generic direct SQL query to the site DB
1186
  *
1187
  * The reason: https://make.wordpress.org/core/2017/10/31/changed-behaviour-of-esc_sql-in-wordpress-4-8-3/
1188
  *
1189
+ * @param $query string An SQL query
1190
  *
1191
+ * @return bool|mysqli_result
1192
  * @since 6.0
1193
  */
1194
+ function cerber_db_query( $query ) {
1195
  global $wpdb;
1196
+ static $db;
1197
+
1198
+ if ( ! isset( $db ) || ! is_object( $db ) ) {
1199
+ // Check for connected DB handler
1200
+ if ( ! is_object( $wpdb ) || empty( $wpdb->dbh ) ) {
1201
+ if ( ! $db = cerber_direct_db_connect() ) {
1202
+ return false;
1203
+ }
1204
+ }
1205
+ else {
1206
+ $db = $wpdb;
1207
  }
1208
  }
1209
+
 
 
1210
  if ( $db->use_mysqli ) {
1211
  $ret = mysqli_query( $db->dbh, $query );
1212
  }
1213
  else {
1214
+ $ret = mysql_query( $query, $db->dbh ); // For compatibility reason
1215
  }
1216
 
1217
  return $ret;
1222
  *
1223
  * @return bool|wpdb
1224
  */
1225
+ function cerber_direct_db_connect() {
1226
  if ( ! defined( 'CRB_ABSPATH' ) ) {
1227
  define( 'CRB_ABSPATH', dirname( __FILE__, 4 ) );
1228
  }
1229
+ $db_class = CRB_ABSPATH . '/wp-includes/wp-db.php';
1230
  $wp_config = CRB_ABSPATH . '/wp-config.php';
1231
+ if ( file_exists( $db_class ) && $config = file_get_contents( $wp_config ) ) {
1232
+ $config = str_replace( '<?php', '', $config );
1233
+ $config = str_replace( '?>', '', $config );
1234
+ ob_start();
1235
+ @eval( $config ); // This eval is OK. Getting site DB parameters.
1236
+ ob_end_clean();
1237
+ if ( defined( 'DB_USER' ) && defined( 'DB_PASSWORD' ) && defined( 'DB_NAME' ) && defined( 'DB_HOST' ) ) {
1238
+ require_once( $db_class );
1239
+
1240
+ return new wpdb( DB_USER, DB_PASSWORD, DB_NAME, DB_HOST );
 
 
 
 
 
1241
  }
1242
  }
1243
 
1244
  return false;
1245
  }
1246
 
1247
+ /**
1248
+ * Remove comments from a given piece of code
1249
+ *
1250
+ * @param string $string
1251
+ *
1252
+ * @return mixed
1253
+ */
1254
+ function cerber_remove_comments( $string = '' ) {
1255
+ return preg_replace( '/#.*/', '', preg_replace( '#//.*#', '', preg_replace( '#/\*(?:[^*]*(?:\*(?!/))*)*\*/#', '', ( $string ) ) ) );
1256
+ }
1257
+
1258
  /**
1259
  * Set Cerber Groove to logged in user browser
1260
  *
1306
  Get the special public Cerber Sign for using with cookies
1307
  */
1308
  function cerber_get_groove_x( $regenerate = false ) {
1309
+ $groove_x = array();
1310
+
1311
  if ( ! $regenerate ) {
1312
  $groove_x = cerber_get_site_option( 'cerber-groove-x' );
1313
  }
1356
  }
1357
 
1358
  // Update all rules in a section - adding/deleting
1359
+ return cerber_update_htaccess( CERBER_MARKER1, $rules );
1360
+ }
1361
+
1362
+ /**
1363
+ * Remove Cerber rules from the .htaccess file
1364
+ *
1365
+ */
1366
+ function cerber_htaccess_clean_up(){
1367
+ cerber_update_htaccess( CERBER_MARKER1, array() );
1368
  }
1369
 
1370
  /**
1379
  if ( ! $marker ) {
1380
  return false;
1381
  }
1382
+ if ( ! $htaccess_file = cerber_get_htaccess_file() ) {
1383
  return 'ERROR: Unable to modify the .htaccess file';
1384
  }
1385
  require_once( ABSPATH . 'wp-admin/includes/misc.php' );
1386
+ if ( ! apache_mod_loaded( 'mod_rewrite', true ) ) {
1387
  return 'ERROR: Apache mod_rewrite is not enabled';
1388
  }
1389
 
1390
+ $result = insert_with_markers( $htaccess_file, CERBER_MARKER1, $rules );
1391
 
1392
  if ( $result || $result === 0 ) {
1393
  $result = true;
1399
  return $result;
1400
  }
1401
 
1402
+ /**
1403
+ * Return .htaccess filename with full path
1404
+ *
1405
+ * @return bool|string full filename if the file can be written, false otherwise
1406
+ */
1407
+ function cerber_get_htaccess_file() {
1408
  require_once( ABSPATH . 'wp-admin/includes/file.php' );
1409
  $home_path = get_home_path();
1410
+ $file = $home_path . '.htaccess';
1411
+ if ( ! is_writable( $file ) ) {
1412
  // should we create the file?
1413
  return false;
1414
  }
1415
 
1416
+ return $file;
1417
+ }
1418
+
1419
+ /**
1420
+ * Prepare files (install/deinstall) for different boot modes
1421
+ *
1422
+ * @param $mode int A plugin boot mode
1423
+ * @param $old_mode int
1424
+ *
1425
+ * @return bool|WP_Error
1426
+ * @since 6.3
1427
+ */
1428
+ function cerber_set_boot_mode( $mode = null, $old_mode = null ) {
1429
+ if ( $mode === null ) {
1430
+ $mode = crb_get_settings( 'boot-mode' );
1431
+ }
1432
+ $source = dirname( cerber_plugin_file() ) . '/modules/aaa-wp-cerber.php';
1433
+ $target = WPMU_PLUGIN_DIR . '/aaa-wp-cerber.php';
1434
+ if ( $mode == 1 ) {
1435
+ if ( file_exists( $target ) ) {
1436
+ if ( sha1_file( $source, true ) == sha1_file( $target, true ) ) {
1437
+ return true;
1438
+ }
1439
+ }
1440
+ if ( ! is_dir( WPMU_PLUGIN_DIR ) ) {
1441
+ if ( ! mkdir( WPMU_PLUGIN_DIR, 0755, true ) ) {
1442
+ // TODO: try to set permissions for the parent folder
1443
+ return new WP_Error( 'cerber-boot', __( 'Unable to create the directory', 'wp-cerber' ) . ' ' . WPMU_PLUGIN_DIR );
1444
+ }
1445
+ }
1446
+ if ( ! copy( $source, $target ) ) {
1447
+ if ( ! wp_is_writable( WPMU_PLUGIN_DIR ) ) {
1448
+ return new WP_Error( 'cerber-boot', __( 'Destination folder access denied', 'wp-cerber' ) . ' ' . WPMU_PLUGIN_DIR );
1449
+ }
1450
+ elseif ( ! file_exists( $source ) ) {
1451
+ return new WP_Error( 'cerber-boot', __( 'File not found', 'wp-cerber' ) . ' ' . $source );
1452
+ }
1453
+
1454
+ return new WP_Error( 'cerber-boot', __( 'Unable to copy the file', 'wp-cerber' ) . ' ' . $source . ' to the folder ' . WPMU_PLUGIN_DIR );
1455
+ }
1456
+ }
1457
+ else {
1458
+ if ( file_exists( $target ) ) {
1459
+ if ( ! unlink( $target ) ) {
1460
+ return new WP_Error( 'cerber-boot', __( 'Unable to delete the file', 'wp-cerber' ) . ' ' . $target );
1461
+ }
1462
+ }
1463
+
1464
+ return true;
1465
+ }
1466
+
1467
+ return true;
1468
+ }
1469
+
1470
+ /**
1471
+ * How the plugin was loaded (initialized)
1472
+ *
1473
+ * @return int
1474
+ * @since 6.3
1475
+ */
1476
+ function cerber_get_mode() {
1477
+ if ( function_exists( 'cerber_mode' ) && defined( 'CERBER_MODE' ) ) {
1478
+ return cerber_mode();
1479
+ }
1480
+
1481
+ return 0;
1482
  }
dashboard.php CHANGED
@@ -382,8 +382,7 @@ function cerber_admin_request(){
382
  else {
383
  cerber_admin_notice( __( 'Unable to send email to', 'wp-cerber' ) . ' ' . $to );
384
  }
385
- wp_safe_redirect( remove_query_arg( 'testnotify' ) ); // mandatory!
386
- exit; // mandatory!
387
  }
388
  elseif ( $ip = cerber_get_get( 'lockdelete' ) ) {
389
  if ( cerber_block_delete( $ip ) ) {
@@ -396,8 +395,7 @@ function cerber_admin_request(){
396
  elseif ( isset( $_GET['subscribe'] ) ) {
397
  $mode = ( 'on' == $_GET['subscribe'] ) ? 'on' : 'off';
398
  cerber_subscribe( $mode );
399
- wp_safe_redirect( remove_query_arg( 'subscribe' ) ); // mandatory!
400
- exit; // mandatory!
401
  }
402
  elseif ( isset( $_GET['citadel'] ) && $_GET['citadel'] == 'deactivate' ) {
403
  cerber_disable_citadel();
@@ -405,15 +403,13 @@ function cerber_admin_request(){
405
  elseif ( isset( $_GET['load_settings'] ) && $_GET['load_settings'] == 'default' ) {
406
  cerber_load_defaults();
407
  cerber_admin_message( __( 'Settings saved', 'wp-cerber' ) );
408
- wp_safe_redirect( remove_query_arg( array( 'load_settings', 'cerber_nonce' ) ) ); // mandatory!
409
- exit; // mandatory!
410
  }
411
  elseif ( isset( $_GET['force_repair_db'] ) ) {
412
  cerber_create_db();
413
  cerber_upgrade_db( true );
414
  cerber_admin_message( 'Cerber\'s tables has been upgraded' );
415
- wp_safe_redirect( remove_query_arg( array( 'force_repair_db', 'cerber_nonce' ) ) ); // mandatory!
416
- exit; // mandatory!
417
  }
418
  elseif ( isset( $_GET['truncate'] ) ) {
419
  $table = $_GET['truncate'];
@@ -424,14 +420,17 @@ function cerber_admin_request(){
424
  }
425
  else cerber_admin_message( $wpdb->last_error );
426
  }
427
- wp_safe_redirect( remove_query_arg( array( 'truncate', 'cerber_nonce' ) ) ); // mandatory!
428
- exit; // mandatory!
429
  }
430
  elseif ( isset( $_GET['force_check_nodes'] ) ) {
431
  $best = lab_check_nodes( true );
432
  cerber_admin_message( 'Cerber Lab\'s nodes has been checked. The closest node: ' . $best );
433
- wp_safe_redirect( remove_query_arg( array( 'force_check_nodes', 'cerber_nonce' ) ) ); // mandatory!
434
- exit; // mandatory!
 
 
 
 
435
  }
436
  }
437
 
@@ -452,6 +451,14 @@ function cerber_admin_request(){
452
 
453
  }
454
 
 
 
 
 
 
 
 
 
455
  /**
456
  * Generate export CSV file using $_GET parameters (via cerber_activity_query())
457
  *
@@ -1053,6 +1060,15 @@ function cerber_is_admin_page( $force = true, $params = array() ) {
1053
  return false;
1054
  }
1055
 
 
 
 
 
 
 
 
 
 
1056
  // Users -------------------------------------------------------------------------------------
1057
 
1058
  add_filter('users_list_table_query_args' , function ($args) {
@@ -1268,8 +1284,8 @@ function cerber_show_help() {
1268
 
1269
  <?php echo $support; ?>
1270
 
1271
- <p><span class="dashicons-before dashicons-book-alt"></span> <a href="https://wpcerber.com/toc/" target="_blank">Read articles on wpcerber.com</a></p>
1272
- <p><span class="dashicons-before dashicons-format-chat"></span> <a href="https://wordpress.org/support/plugin/wp-cerber">Get answer on the support forum</a></p>
1273
 
1274
 
1275
  <form style="margin-top: 2em;" action="https://wpcerber.com" target="_blank">
@@ -1277,23 +1293,36 @@ function cerber_show_help() {
1277
  <input type="text" style="width: 80%;" name="s" placeholder="Enter term to search"><input type="submit" value="Search" class="button button-primary">
1278
  </form>
1279
 
 
 
 
 
 
 
 
 
 
 
 
1280
  </td>
1281
  <td>
1282
  <h3>What is IP address of your computer?</h3>
1283
 
1284
  <p>To find out your current IP address go to this page: <a href="https://wpcerber.com/what-is-my-ip/">What is my IP</a>. If you see a different IP address on the Activity tab for your login or logout events you probably need to check <b><?php _e('My site is behind a reverse proxy','wp-cerber'); ?></b>.</p>
1285
  <p>
1286
- <span class="dashicons-before dashicons-book-alt"> <a href="https://wpcerber.com/wordpress-ip-address-detection/">Solving problem with incorrect IP address detection</a>
1287
  </p>
1288
 
1289
 
1290
  <h3>Setting up antispam protection</h3>
1291
 
1292
  <p>
1293
- Cerber antispam and bot detection engine is capable to protect virtually any form on a website. It’s a great alternative to reCAPTCHA.
1294
  </p>
1295
  <p>
1296
- <span class="dashicons-before dashicons-book-alt"> <a href="https://wpcerber.com/antispam-for-wordpress-contact-forms/">Find out more about antispam protection</a>
 
 
1297
  </p>
1298
 
1299
 
@@ -1303,13 +1332,18 @@ function cerber_show_help() {
1303
  WP Cerber allows you to easily enable desktop and mobile notifications and get notifications instantly and for free. In a desktop browser, you will get popup messages even if you logged out of your WordPress.
1304
  Before you start receiving notifications you need to install a free Pushbullet mobile application on your mobile device or free browser extension available for Chrome, Firefox and Opera.
1305
  </p>
1306
- <p><span class="dashicons-before dashicons-book-alt"></span>
1307
  <a href="https://wpcerber.com/wordpress-mobile-and-browser-notifications-pushbullet/">A three steps instruction how to set up push notifications</a>
1308
  </p>
1309
- <p><span class="dashicons-before dashicons-book-alt"></span>
1310
  <a href="https://wpcerber.com/wordpress-notifications-made-easy/">How to get alerts for specific activity on your website</a>
1311
  </p>
1312
 
 
 
 
 
 
1313
  </td>
1314
  </tr>
1315
  </table>
@@ -1437,7 +1471,7 @@ function cerber_show_dashboard() {
1437
  echo '<table class="cerber-margin"><tr><td><h2 style="margin-bottom:0.5em; margin-right: 1em;">' . __( 'Activity', 'wp-cerber' ) . '</h2></td><td>' . $nav_links . '</td></tr></table>';
1438
 
1439
  cerber_show_activity( array(
1440
- 'filter_activity' => array( 1, 2, 5, 10, 11, 12, 16, 17, 18, 19, 40, 41, 42, 50, 51, 52, 53, 54, 55, 70, 71 ),
1441
  'per_page' => 10,
1442
  'no_navi' => true,
1443
  'no_export' => true,
@@ -1512,17 +1546,20 @@ function cerber_show_aside($page){
1512
  ';
1513
 
1514
  // 22.01.2017
1515
- $aside[] = '<a class="crb-button-one" style="text-align:center; padding-top: 1.5em; padding-bottom: 1.5em; background-color: #C92E5C;" href="https://wpcerber.com/pro/" target="_blank">
 
1516
  <span class="dashicons dashicons-awards"></span><span class="dashicons dashicons-awards"></span><span class="dashicons dashicons-awards"></span><br><br>UPGRADE TO PROFESSIONAL VERSION</a>';
 
1517
 
1518
- }
1519
 
1520
- /*
 
1521
  if (!lab_lab() && !in_array($page,array('geo'))) {
1522
  $aside[] = '<div class="crb-box" id = "crb-donate">
1523
  <div class="crb-box-inner">
1524
  <h3>' . __( 'Donate', 'wp-cerber' ) . '</h3>
1525
- <p>Hi! It\'s Gregory. I am an author of this plugin. Please consider making a donation to support the continued development and free support of this plugin because I spend my free time for that. Any help is greatly appreciated. Thanks!</p>
1526
 
1527
  <div style="text-align:center;">
1528
  <form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
@@ -1820,23 +1857,6 @@ function cerber_db_diag(){
1820
  return $err.implode('<br>',$ret);
1821
  }
1822
 
1823
- function cerber_wp_diag(){
1824
- global $wp_version, $wpdb;
1825
-
1826
- $ret = array();
1827
-
1828
- $ret[] = 'WordPress version: ' . $wp_version;
1829
- $ret[] = 'WordPress options table: '.$wpdb->prefix.'options';
1830
- $ret[] = '<br>Active plugins:<br>';
1831
- $list = get_option('active_plugins');
1832
- foreach($list as $plugin) {
1833
- $data = get_plugin_data(WP_PLUGIN_DIR.'/'.$plugin);
1834
- $ret[] = '- '.$data['Name'].' v. '.$data['Version'];
1835
- }
1836
-
1837
- return implode("<br>",$ret);
1838
- }
1839
-
1840
  /**
1841
  * Creates mini report about given database table
1842
  *
@@ -1944,9 +1964,9 @@ add_action('customize_controls_print_scripts', 'cerber_admin_head' ); // @since
1944
  function cerber_admin_head(){
1945
  global $assets_url, $crb_assets_url, $crb_ajax_loader;
1946
 
1947
- $assets_url = plugin_dir_url( CERBER_FILE ) . 'assets/';
1948
 
1949
- $crb_assets_url = plugin_dir_url( CERBER_FILE ) . 'assets/';
1950
  $crb_ajax_loader = $crb_assets_url . 'ajax-loader.gif';
1951
  $crb_ajax_nonce = wp_create_nonce( 'crb-ajax-admin' );
1952
 
@@ -1979,7 +1999,7 @@ function cerber_admin_head(){
1979
  if (lab_lab()):
1980
  ?>
1981
  <style type="text/css" media="all">
1982
- .actv5, .actv10, .actv11, .actv12, .actv16, .actv17, .actv18, .actv19, .actv41, .actv42, .actv53, .actv54, .actv55, .actv70 {
1983
  padding: 0;
1984
  border-left: none;
1985
  background-color: initial;
@@ -1996,7 +2016,7 @@ function cerber_admin_head(){
1996
  #crb-activity td.acinfo div {
1997
  padding: 0.1em 0 0.1em 0.7em;
1998
  }
1999
- .crb10, .crb11, .crb12, .crb16, .crb17, .crb18, .crb19, .crb41, .crb42, .crb51, .crb52, .crb53, .crb54, .crb55, .crb70, .crb71 {
2000
  /*border-left: 4px solid #FF5733;*/
2001
  font-weight: bold;
2002
  border-left: 6px solid #FF5733;
@@ -2077,7 +2097,13 @@ function cerber_footer_text2($text){
2077
  $pr = '';
2078
  $support = '<a target="_blank" href="https://wordpress.org/support/plugin/wp-cerber">Support Forum</a>';
2079
  }
2080
- return 'WP Cerber Security '.$pr.' '.CERBER_VER.'. | ' . $support;
 
 
 
 
 
 
2081
  }
2082
 
2083
  /*
@@ -2494,7 +2520,7 @@ function crb_country_html($code = null, $ip = null){
2494
 
2495
  function cerber_traffic_page(){
2496
 
2497
- $tab = cerber_get_tab( 'traffic', array( 'traffic', 'ti_settings' ) );
2498
 
2499
  ?>
2500
  <div class="wrap">
@@ -2506,7 +2532,7 @@ function cerber_traffic_page(){
2506
 
2507
  echo '<a href="' . cerber_admin_link('traffic') . '" class="nav-tab ' . ( $tab == 'traffic' ? 'nav-tab-active' : '') . '"><span class="dashicons dashicons-visibility"></span> ' . __('Live traffic') . '</a>';
2508
  echo '<a href="' . cerber_admin_link('ti_settings') . '" class="nav-tab ' . ( $tab == 'ti_settings' ? 'nav-tab-active' : '') . '"><span class="dashicons dashicons-admin-settings"></span> ' . __('Settings') . '</a>';
2509
- //echo '<a href="' . cerber_admin_link('help') . '" class="nav-tab ' . ( $tab == 'help' ? 'nav-tab-active' : '') . '"><span class="dashicons dashicons-editor-help"></span> ' . __('Help','wp-cerber') . '</a>';
2510
 
2511
  echo lab_indicator();
2512
  ?>
@@ -2525,6 +2551,9 @@ function cerber_traffic_page(){
2525
  case 'ti_settings':
2526
  cerber_show_settings_page( 'traffic' );
2527
  break;
 
 
 
2528
  default:
2529
  cerber_show_activity();
2530
  }
@@ -2718,13 +2747,13 @@ function cerber_show_traffic($args = array(), $echo = true){
2718
  // POST fields
2719
 
2720
  if ( ! empty( $fields[1] ) ) {
2721
- $more_details[] = array('', cerber_table_view('Post fields',$fields[1]) );
2722
  }
2723
 
2724
  // GET fields
2725
 
2726
  if ( ! empty( $fields[2] ) ) {
2727
- $more_details[] = array('', cerber_table_view('Get fields',$fields[2]) );
2728
  }
2729
 
2730
  // Files
@@ -3015,6 +3044,7 @@ function cerber_traffic_query($args = array()){
3015
  }
3016
  if ($search['uri']) $where[] = $wpdb->prepare('log.uri LIKE %s','%'.$search['uri'].'%');
3017
  if ($search['fields']) $where[] = $wpdb->prepare('log.request_fields LIKE %s','%'.$search['fields'].'%');
 
3018
  if ($search['date_from']){
3019
  if ($stamp = strtotime('midnight ' . $search['date_from'])){
3020
  $gmt_offset = get_option( 'gmt_offset' ) * 3600;
@@ -3083,22 +3113,7 @@ function cerber_traffic_search(){
3083
  <div id="crb-traffic-form" style="margin: 0 auto; width: 300px;">
3084
  <input type="hidden" value="cerber-traffic" name="page">
3085
 
3086
- <p>URL contains
3087
- <br/><input type="text" name="search_traffic[uri]"></p>
3088
-
3089
- <p>IP address contains or equals
3090
- <br/><input type="text" name="search_traffic[ip]"></p>
3091
-
3092
- <p>User ID equals
3093
- <br/><input type="number" name="filter_user"></p>
3094
-
3095
- <p>POST or GET fields contain
3096
- <br/><input type="text" name="search_traffic[fields]"></p>
3097
-
3098
- <p>HTTP Response Code equals
3099
- <br/><input type="number" name="filter_http_code"></p>
3100
-
3101
- <p style="width: 100%;">Activity
3102
  <?php
3103
  $labels = cerber_get_labels('activity');
3104
  unset( $labels[5], $labels[51], $labels[13], $labels[14], $labels[15] );
@@ -3107,11 +3122,32 @@ function cerber_traffic_search(){
3107
  ?>
3108
  </p>
3109
 
3110
- <p>Date from
3111
- <br/><input type="date" name="search_traffic[date_from]" placeholder="month/day/year"></p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3112
 
3113
- <p>Date to
3114
- <br/><input type="date" name="search_traffic[date_to]" placeholder="month/day/year"></p>
3115
 
3116
  <p><input type="submit" class="button button-primary" value="Search"></p>
3117
  </div>
@@ -3121,7 +3157,7 @@ function cerber_traffic_search(){
3121
 
3122
  <?php
3123
 
3124
- return '<a href="#TB_inline?width=400&height=650&inlineId=cerber-traffic-search" class="thickbox crb-button-tiny crb-button-active" title="Search in the request history">'.__('Advanced search','wp-cerber').'</a>';
3125
 
3126
  }
3127
 
382
  else {
383
  cerber_admin_notice( __( 'Unable to send email to', 'wp-cerber' ) . ' ' . $to );
384
  }
385
+ cerber_safe_redirect('testnotify');
 
386
  }
387
  elseif ( $ip = cerber_get_get( 'lockdelete' ) ) {
388
  if ( cerber_block_delete( $ip ) ) {
395
  elseif ( isset( $_GET['subscribe'] ) ) {
396
  $mode = ( 'on' == $_GET['subscribe'] ) ? 'on' : 'off';
397
  cerber_subscribe( $mode );
398
+ cerber_safe_redirect('subscribe');
 
399
  }
400
  elseif ( isset( $_GET['citadel'] ) && $_GET['citadel'] == 'deactivate' ) {
401
  cerber_disable_citadel();
403
  elseif ( isset( $_GET['load_settings'] ) && $_GET['load_settings'] == 'default' ) {
404
  cerber_load_defaults();
405
  cerber_admin_message( __( 'Settings saved', 'wp-cerber' ) );
406
+ cerber_safe_redirect('load_settings');
 
407
  }
408
  elseif ( isset( $_GET['force_repair_db'] ) ) {
409
  cerber_create_db();
410
  cerber_upgrade_db( true );
411
  cerber_admin_message( 'Cerber\'s tables has been upgraded' );
412
+ cerber_safe_redirect('force_repair_db');
 
413
  }
414
  elseif ( isset( $_GET['truncate'] ) ) {
415
  $table = $_GET['truncate'];
420
  }
421
  else cerber_admin_message( $wpdb->last_error );
422
  }
423
+ cerber_safe_redirect('truncate');
 
424
  }
425
  elseif ( isset( $_GET['force_check_nodes'] ) ) {
426
  $best = lab_check_nodes( true );
427
  cerber_admin_message( 'Cerber Lab\'s nodes has been checked. The closest node: ' . $best );
428
+ cerber_safe_redirect('force_check_nodes');
429
+ }
430
+ elseif ( isset( $_GET['clean_up_the_cache'] ) ) {
431
+ lab_cleanup_cache();
432
+ cerber_admin_message( 'The cache has been cleaned up');
433
+ cerber_safe_redirect('clean_up_the_cache');
434
  }
435
  }
436
 
451
 
452
  }
453
 
454
+ function cerber_safe_redirect($args){
455
+ if (!is_array($args)){
456
+ $args = array($args);
457
+ }
458
+ $args[]='cerber_nonce';
459
+ wp_safe_redirect(remove_query_arg($args));
460
+ exit(); // mandatory!
461
+ }
462
  /**
463
  * Generate export CSV file using $_GET parameters (via cerber_activity_query())
464
  *
1060
  return false;
1061
  }
1062
 
1063
+ function cerber_get_admin_page(){
1064
+ $ret = '';
1065
+ if (!empty($_GET['page'])){
1066
+ $ret = preg_replace('/[^A-Z0-9\_\-]/i','',$_GET['page']);
1067
+ }
1068
+
1069
+ return $ret;
1070
+ }
1071
+
1072
  // Users -------------------------------------------------------------------------------------
1073
 
1074
  add_filter('users_list_table_query_args' , function ($args) {
1284
 
1285
  <?php echo $support; ?>
1286
 
1287
+ <p><span class="dashicons dashicons-before dashicons-book-alt"></span> <a href="https://wpcerber.com/toc/" target="_blank">Read articles on wpcerber.com</a></p>
1288
+ <p><span class="dashicons dashicons-before dashicons-format-chat"></span> <a href="https://wordpress.org/support/plugin/wp-cerber">Get answer on the support forum</a></p>
1289
 
1290
 
1291
  <form style="margin-top: 2em;" action="https://wpcerber.com" target="_blank">
1293
  <input type="text" style="width: 80%;" name="s" placeholder="Enter term to search"><input type="submit" value="Search" class="button button-primary">
1294
  </form>
1295
 
1296
+ <h3>Traffic Inspector</h3>
1297
+
1298
+ <p>Traffic Inspector is a set of specialized request inspection algorithms that acts as an additional protection layer (firewall) for your WordPress</p>
1299
+
1300
+ <p>
1301
+ <span class="dashicons dashicons-before dashicons-book-alt"></span> <a href="https://wpcerber.com/traffic-inspector-in-a-nutshell/">Traffic Inspector in a nutshell</a>
1302
+ </p>
1303
+ <p><span class="dashicons dashicons-before dashicons-book-alt"></span> <a href="https://wpcerber.com/wordpress-traffic-inspector-how-to/">Traffic Inspector and logging how to</a>
1304
+ </p>
1305
+
1306
+
1307
  </td>
1308
  <td>
1309
  <h3>What is IP address of your computer?</h3>
1310
 
1311
  <p>To find out your current IP address go to this page: <a href="https://wpcerber.com/what-is-my-ip/">What is my IP</a>. If you see a different IP address on the Activity tab for your login or logout events you probably need to check <b><?php _e('My site is behind a reverse proxy','wp-cerber'); ?></b>.</p>
1312
  <p>
1313
+ <span class="dashicons dashicons-before dashicons-book-alt"></span> <a href="https://wpcerber.com/wordpress-ip-address-detection/">Solving problem with incorrect IP address detection</a>
1314
  </p>
1315
 
1316
 
1317
  <h3>Setting up antispam protection</h3>
1318
 
1319
  <p>
1320
+ The Cerber antispam and bot detection engine is capable to protect virtually any form on a website. It’s a great alternative to reCAPTCHA.
1321
  </p>
1322
  <p>
1323
+ <span class="dashicons dashicons-before dashicons-book-alt"></span> <a href="https://wpcerber.com/how-to-stop-spam-user-registrations-wordpress/">How to stop spam user registrations on your WordPress</a>
1324
+ </p>
1325
+ <p><span class="dashicons dashicons-before dashicons-book-alt"></span> <a href="https://wpcerber.com/antispam-for-wordpress-contact-forms/">Antispam protection for contact forms</a>
1326
  </p>
1327
 
1328
 
1332
  WP Cerber allows you to easily enable desktop and mobile notifications and get notifications instantly and for free. In a desktop browser, you will get popup messages even if you logged out of your WordPress.
1333
  Before you start receiving notifications you need to install a free Pushbullet mobile application on your mobile device or free browser extension available for Chrome, Firefox and Opera.
1334
  </p>
1335
+ <p><span class="dashicons dashicons-before dashicons-book-alt"></span>
1336
  <a href="https://wpcerber.com/wordpress-mobile-and-browser-notifications-pushbullet/">A three steps instruction how to set up push notifications</a>
1337
  </p>
1338
+ <p><span class="dashicons dashicons-before dashicons-book-alt"></span>
1339
  <a href="https://wpcerber.com/wordpress-notifications-made-easy/">How to get alerts for specific activity on your website</a>
1340
  </p>
1341
 
1342
+ <h3>WordPress security explained</h3>
1343
+ <p><span class="dashicons dashicons-before dashicons-book-alt"></span> <a href="https://wpcerber.com/why-recaptcha-does-not-protect-wordpress/">Why does reCAPTCHA not protect WordPress against bots and brute-force attacks?</a></p>
1344
+ <p><span class="dashicons dashicons-before dashicons-book-alt"></span> <a href="https://wpcerber.com/why-we-need-to-use-custom-login-url/">Why you need to use Custom login URL for your WordPress</a></p>
1345
+ <p><span class="dashicons-before dashicons-book-alt"></span> <a href="https://wpcerber.com/why-its-important-to-restrict-access-to-rest-api/">Why it's important to restrict access to the WP REST API</a></p>
1346
+ <p><span class="dashicons-before dashicons-book-alt"></span> <a href="https://wpcerber.com/mitigating-brute-force-dos-and-ddos-attacks/">Brute-force, DoS, and DDoS attacks - what's the difference?</a></p>
1347
  </td>
1348
  </tr>
1349
  </table>
1471
  echo '<table class="cerber-margin"><tr><td><h2 style="margin-bottom:0.5em; margin-right: 1em;">' . __( 'Activity', 'wp-cerber' ) . '</h2></td><td>' . $nav_links . '</td></tr></table>';
1472
 
1473
  cerber_show_activity( array(
1474
+ 'filter_activity' => array( 1, 2, 5, 10, 11, 12, 16, 17, 18, 19, 40, 41, 42, 50, 51, 52, 53, 54, 55, 56),
1475
  'per_page' => 10,
1476
  'no_navi' => true,
1477
  'no_export' => true,
1546
  ';
1547
 
1548
  // 22.01.2017
1549
+ /*
1550
+ * $aside[] = '<a class="crb-button-one" style="text-align:center; padding-top: 1.5em; padding-bottom: 1.5em; background-color: #C92E5C;" href="https://wpcerber.com/pro/" target="_blank">
1551
  <span class="dashicons dashicons-awards"></span><span class="dashicons dashicons-awards"></span><span class="dashicons dashicons-awards"></span><br><br>UPGRADE TO PROFESSIONAL VERSION</a>';
1552
+ */
1553
 
1554
+ $aside[] = '<a href="https://wpcerber.com/pro/" target="_blank"><img src="'.$crb_assets_url.'bn2ra.png" /></a>';
1555
 
1556
+ }
1557
+ /*
1558
  if (!lab_lab() && !in_array($page,array('geo'))) {
1559
  $aside[] = '<div class="crb-box" id = "crb-donate">
1560
  <div class="crb-box-inner">
1561
  <h3>' . __( 'Donate', 'wp-cerber' ) . '</h3>
1562
+ <p>Please consider making a donation to support the continued development and free support of this plugin. Thanks!</p>
1563
 
1564
  <div style="text-align:center;">
1565
  <form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
1857
  return $err.implode('<br>',$ret);
1858
  }
1859
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1860
  /**
1861
  * Creates mini report about given database table
1862
  *
1964
  function cerber_admin_head(){
1965
  global $assets_url, $crb_assets_url, $crb_ajax_loader;
1966
 
1967
+ $assets_url = cerber_plugin_dir_url() . 'assets/';
1968
 
1969
+ $crb_assets_url = cerber_plugin_dir_url() . 'assets/';
1970
  $crb_ajax_loader = $crb_assets_url . 'ajax-loader.gif';
1971
  $crb_ajax_nonce = wp_create_nonce( 'crb-ajax-admin' );
1972
 
1999
  if (lab_lab()):
2000
  ?>
2001
  <style type="text/css" media="all">
2002
+ .actv5, .actv10, .actv11, .actv12, .actv16, .actv17, .actv18, .actv19, .actv41, .actv42, .actv53, .actv54, .actv55, .actv56, .actv70 {
2003
  padding: 0;
2004
  border-left: none;
2005
  background-color: initial;
2016
  #crb-activity td.acinfo div {
2017
  padding: 0.1em 0 0.1em 0.7em;
2018
  }
2019
+ .crb10, .crb11, .crb12, .crb16, .crb17, .crb18, .crb19, .crb41, .crb42, .crb51, .crb52, .crb53, .crb54, .crb55, .crb56, .crb70, .crb71 {
2020
  /*border-left: 4px solid #FF5733;*/
2021
  font-weight: bold;
2022
  border-left: 6px solid #FF5733;
2097
  $pr = '';
2098
  $support = '<a target="_blank" href="https://wordpress.org/support/plugin/wp-cerber">Support Forum</a>';
2099
  }
2100
+ if (1 == cerber_get_mode()){
2101
+ $mode = 'in Standard mode';
2102
+ }
2103
+ else {
2104
+ $mode = 'in Legacy mode';
2105
+ }
2106
+ return 'WP Cerber Security '.$pr.' '.CERBER_VER.'. '.$mode.' | ' . $support;
2107
  }
2108
 
2109
  /*
2520
 
2521
  function cerber_traffic_page(){
2522
 
2523
+ $tab = cerber_get_tab( 'traffic', array( 'traffic', 'ti_settings', 'help' ) );
2524
 
2525
  ?>
2526
  <div class="wrap">
2532
 
2533
  echo '<a href="' . cerber_admin_link('traffic') . '" class="nav-tab ' . ( $tab == 'traffic' ? 'nav-tab-active' : '') . '"><span class="dashicons dashicons-visibility"></span> ' . __('Live traffic') . '</a>';
2534
  echo '<a href="' . cerber_admin_link('ti_settings') . '" class="nav-tab ' . ( $tab == 'ti_settings' ? 'nav-tab-active' : '') . '"><span class="dashicons dashicons-admin-settings"></span> ' . __('Settings') . '</a>';
2535
+ echo '<a href="' . cerber_admin_link('help',array('page'=>cerber_get_admin_page())) . '" class="nav-tab ' . ( $tab == 'help' ? 'nav-tab-active' : '') . '"><span class="dashicons dashicons-editor-help"></span> ' . __('Help','wp-cerber') . '</a>';
2536
 
2537
  echo lab_indicator();
2538
  ?>
2551
  case 'ti_settings':
2552
  cerber_show_settings_page( 'traffic' );
2553
  break;
2554
+ case 'help':
2555
+ cerber_show_help();
2556
+ break;
2557
  default:
2558
  cerber_show_activity();
2559
  }
2747
  // POST fields
2748
 
2749
  if ( ! empty( $fields[1] ) ) {
2750
+ $more_details[] = array('', cerber_table_view('POST fields',$fields[1]) );
2751
  }
2752
 
2753
  // GET fields
2754
 
2755
  if ( ! empty( $fields[2] ) ) {
2756
+ $more_details[] = array('', cerber_table_view('GET fields',$fields[2]) );
2757
  }
2758
 
2759
  // Files
3044
  }
3045
  if ($search['uri']) $where[] = $wpdb->prepare('log.uri LIKE %s','%'.$search['uri'].'%');
3046
  if ($search['fields']) $where[] = $wpdb->prepare('log.request_fields LIKE %s','%'.$search['fields'].'%');
3047
+ if ($search['details']) $where[] = $wpdb->prepare('log.request_details LIKE %s','%'.$search['details'].'%');
3048
  if ($search['date_from']){
3049
  if ($stamp = strtotime('midnight ' . $search['date_from'])){
3050
  $gmt_offset = get_option( 'gmt_offset' ) * 3600;
3113
  <div id="crb-traffic-form" style="margin: 0 auto; width: 300px;">
3114
  <input type="hidden" value="cerber-traffic" name="page">
3115
 
3116
+ <p style="width: 100%;"><label>Activity</label>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3117
  <?php
3118
  $labels = cerber_get_labels('activity');
3119
  unset( $labels[5], $labels[51], $labels[13], $labels[14], $labels[15] );
3122
  ?>
3123
  </p>
3124
 
3125
+ <p><label for="search-traffic-url">URL contains</label>
3126
+ <br/><input id="search-traffic-url" type="text" name="search_traffic[uri]"></p>
3127
+
3128
+ <p><label for="search-traffic-ip">IP address contains or equals</label>
3129
+ <br/><input id="search-traffic-ip" type="text" name="search_traffic[ip]"></p>
3130
+
3131
+ <p><label for="filter-method">Request method</label>
3132
+ <select id="filter-method" name="filter_method"><option value="0">Any</option><option>GET</option><option>POST</option></select></p>
3133
+
3134
+ <p><label for="filter-user">User ID equals</label>
3135
+ <br/><input id="filter-user" type="number" name="filter_user"></p>
3136
+
3137
+ <p><label for="search-traffic-fields">POST or GET fields contain</label>
3138
+ <br/><input id="search-traffic-fields" type="text" name="search_traffic[fields]"></p>
3139
+
3140
+ <p><label for="search-traffic-details">Miscellaneous details contains</label>
3141
+ <br/><input id="search-traffic-details" type="text" name="search_traffic[details]"></p>
3142
+
3143
+ <p><label for="filter-http-code">HTTP Response Code equals</label>
3144
+ <br/><input id="filter-http-code" type="number" name="filter_http_code"></p>
3145
+
3146
+ <p><label for="search-traffic-date-from">Date from</label>
3147
+ <br/><input id="search-traffic-date-from" type="date" name="search_traffic[date_from]" placeholder="month/day/year"></p>
3148
 
3149
+ <p><label for="search-traffic-date-to">Date to</label>
3150
+ <br/><input id="search-traffic-date-to" type="date" name="search_traffic[date_to]" placeholder="month/day/year"></p>
3151
 
3152
  <p><input type="submit" class="button button-primary" value="Search"></p>
3153
  </div>
3157
 
3158
  <?php
3159
 
3160
+ return '<a href="#TB_inline?width=400&height=720&inlineId=cerber-traffic-search" class="thickbox crb-button-tiny crb-button-active" title="Search in the request history">'.__('Advanced search','wp-cerber').'</a>';
3161
 
3162
  }
3163
 
languages/wp-cerber-zh_CN.mo ADDED
Binary file
languages/wp-cerber-zh_CN.po ADDED
@@ -0,0 +1,1771 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ msgid ""
2
+ msgstr ""
3
+ "MIME-Version: 1.0\n"
4
+ "Content-Type: text/plain; charset=UTF-8\n"
5
+ "Content-Transfer-Encoding: 8bit\n"
6
+ "X-Generator: POEditor.com\n"
7
+ "Project-Id-Version: WP Cerber Security\n"
8
+ "Language: zh-CN\n"
9
+ "Plural-Forms: nplurals=1; plural=0;\n"
10
+
11
+ #: ../settings.php:73
12
+ msgid "Limit login attempts"
13
+ msgstr "限制登入尝试"
14
+
15
+ #: ../settings.php:74
16
+ msgid "Attempts"
17
+ msgstr "尝试"
18
+
19
+ #: ../settings.php:75
20
+ msgid "Lockout duration"
21
+ msgstr "锁定时长"
22
+
23
+ #: ../settings.php:75 ../settings.php:94
24
+ msgid "minutes"
25
+ msgstr "分钟"
26
+
27
+ #: ../settings.php:76
28
+ msgid "Aggressive lockout"
29
+ msgstr "激进屏蔽"
30
+
31
+ #: ../settings.php:79
32
+ msgid "Site connection"
33
+ msgstr "网站连接"
34
+
35
+ #: ../settings.php:81
36
+ msgid "Proactive security rules"
37
+ msgstr "主动安全规则"
38
+
39
+ #: ../settings.php:82
40
+ msgid "Block subnet"
41
+ msgstr "锁定subnet"
42
+
43
+ #: ../settings.php:85
44
+ msgid "Request wp-login.php"
45
+ msgstr "请求/wp-login.php/"
46
+
47
+ #: ../settings.php:85
48
+ msgid "Immediately block IP after any request to wp-login.php"
49
+ msgstr "立即锁定任何请求/wp-login.php/的IP"
50
+
51
+ #: ../settings.php:84
52
+ msgid "Redirect dashboard requests"
53
+ msgstr "重定向Wordpress控制面板请求"
54
+
55
+ #: ../settings.php:88
56
+ msgid "Custom login page"
57
+ msgstr "自定义登入页"
58
+
59
+ #: ../settings.php:89
60
+ msgid "Custom login URL"
61
+ msgstr "自定义登入页URL"
62
+
63
+ #: ../settings.php:89
64
+ msgid "must not overlap with the existing pages or posts slug"
65
+ msgstr "不能与已存在的页面或文章冲突"
66
+
67
+ #: ../settings.php:90
68
+ msgid "Disable wp-login.php"
69
+ msgstr "禁用/wp-login.php/"
70
+
71
+ #: ../settings.php:90
72
+ msgid "Block direct access to wp-login.php and return HTTP 404 Not Found Error"
73
+ msgstr "屏蔽直接接入/wp-login.php/并显示404页面"
74
+
75
+ #: ../dashboard.php:1209 ../settings.php:92
76
+ msgid "Citadel mode"
77
+ msgstr "要塞模式"
78
+
79
+ #: ../settings.php:93
80
+ msgid "Threshold"
81
+ msgstr "阈值"
82
+
83
+ #: ../settings.php:94
84
+ msgid "Duration"
85
+ msgstr "时长"
86
+
87
+ #: ../cerber-load.php:3837 ../settings.php:78 ../settings.php:95 ../settings.php:
88
+ #: 404
89
+ msgid "Notifications"
90
+ msgstr "提醒"
91
+
92
+ #: ../settings.php:95
93
+ msgid "Send notification to admin email"
94
+ msgstr "向管理员邮箱发送提醒"
95
+
96
+ #: ../cerber-load.php:3834 ../settings.php:397 ../cerber-tools.php:88 ../cerber-
97
+ #: tools.php:97 ../cerber-tools.php:178
98
+ msgid "Access Lists"
99
+ msgstr "接入列表"
100
+
101
+ #: ../dashboard.php:1227 ../dashboard.php:1437 ../cerber-load.php:3593 ..
102
+ #: /settings.php:97 ../settings.php:388
103
+ msgid "Activity"
104
+ msgstr "活动"
105
+
106
+ #: ../settings.php:392
107
+ msgid "Lockouts"
108
+ msgstr "锁定"
109
+
110
+ #: ../settings.php:513 ../settings.php:635
111
+ msgid "%s allowed retries in %s minutes"
112
+ msgstr "%s 次重试在 %s 分钟内"
113
+
114
+ #: ../settings.php:535 ../settings.php:657
115
+ msgid "Enable after %s failed login attempts in last %s minutes"
116
+ msgstr "选项开启于 %s 次登入失败在 %s 分钟内"
117
+
118
+ #: ../dashboard.php:93 ../dashboard.php:652 ../dashboard.php:2826 ../cerber-load.
119
+ #: php:3602
120
+ msgid "IP"
121
+ msgstr "IP"
122
+
123
+ #: ../dashboard.php:491 ../dashboard.php:655 ../dashboard.php:2824
124
+ msgid "Date"
125
+ msgstr "日期"
126
+
127
+ #: ../dashboard.php:491 ../dashboard.php:657 ../dashboard.php:2829
128
+ msgid "Local User"
129
+ msgstr "本地用户"
130
+
131
+ #: ../dashboard.php:491 ../dashboard.php:658 ../cerber-load.php:3610
132
+ msgid "Username used"
133
+ msgstr "使用的用户名"
134
+
135
+ #: ../dashboard.php:112
136
+ msgid "Showing last %d records from %d"
137
+ msgstr "显示最近的 %d 记录从 %d"
138
+
139
+ #: ../common.php:708
140
+ msgid "Logged in"
141
+ msgstr "登入"
142
+
143
+ #: ../common.php:709
144
+ msgid "Logged out"
145
+ msgstr "登出"
146
+
147
+ #: ../common.php:710
148
+ msgid "Login failed"
149
+ msgstr "登入失败"
150
+
151
+ #: ../common.php:713
152
+ msgid "IP blocked"
153
+ msgstr "IP被锁定"
154
+
155
+ #: ../common.php:714
156
+ msgid "Subnet blocked"
157
+ msgstr ""
158
+
159
+ #: ../common.php:716
160
+ msgid "Citadel activated!"
161
+ msgstr "要塞模式已被激活!"
162
+
163
+ #: ../dashboard.php:632 ../dashboard.php:836 ../dashboard.php:2662 ../common.php:
164
+ #: 753
165
+ msgid "Locked out"
166
+ msgstr "锁定"
167
+
168
+ #: ../common.php:754
169
+ msgid "IP blacklisted"
170
+ msgstr "黑名单IP"
171
+
172
+ #: ../common.php:731
173
+ msgid "Password changed"
174
+ msgstr "密码已更改"
175
+
176
+ #: ../dashboard.php:86 ../dashboard.php:159
177
+ msgid "Remove"
178
+ msgstr "移除"
179
+
180
+ #: ../dashboard.php:390
181
+ msgid "Lockout for %s was removed"
182
+ msgstr "%s 的锁定已被移除"
183
+
184
+ #: ../dashboard.php:131 ../dashboard.php:627 ../dashboard.php:830 ../dashboard.
185
+ #: php:1207 ../dashboard.php:2657 ../cerber-load.php:3826 ../settings.php:77 ..
186
+ #: /settings.php:358
187
+ msgid "White IP Access List"
188
+ msgstr "IP白名单"
189
+
190
+ #: ../dashboard.php:133 ../dashboard.php:628 ../dashboard.php:833 ../dashboard.
191
+ #: php:1208 ../dashboard.php:2658
192
+ msgid "Black IP Access List"
193
+ msgstr "IP黑名单"
194
+
195
+ #: ../dashboard.php:165
196
+ msgid "List is empty"
197
+ msgstr "列表为空"
198
+
199
+ #: ../dashboard.php:202
200
+ msgid "Address %s was added to White IP Access List"
201
+ msgstr "地址 %s 已被加入IP白名单"
202
+
203
+ #: ../dashboard.php:216
204
+ msgid "Address %s was added to Black IP Access List"
205
+ msgstr "地址 %s 已被加入IP黑名单"
206
+
207
+ #: ../cerber-load.php:3075
208
+ msgid "Citadel mode is activated after %d failed login attempts in %d minutes."
209
+ msgstr "在 %d 次失败登入尝试后,要塞模式已激活 %d 分钟。"
210
+
211
+ #: ../dashboard.php:1592
212
+ msgid "View Activity"
213
+ msgstr "查看活动"
214
+
215
+ #: ../dashboard.php:2514 ../cerber-tools.php:87 ../cerber-tools.php:96
216
+ msgid "Settings"
217
+ msgstr "设置"
218
+
219
+ #: ../dashboard.php:1073
220
+ msgid "Last login"
221
+ msgstr "最后登入"
222
+
223
+ #: ../dashboard.php:1106 ../dashboard.php:1190
224
+ msgid "Never"
225
+ msgstr "永不"
226
+
227
+ #: ../dashboard.php:1483
228
+ msgid "Are you sure?"
229
+ msgstr "确定操作?"
230
+
231
+ #: ../dashboard.php:1284 ../settings.php:79
232
+ msgid "My site is behind a reverse proxy"
233
+ msgstr "网站基于反向代理"
234
+
235
+ #: ../settings.php:83
236
+ msgid "Non-existent users"
237
+ msgstr "不存在的用户名"
238
+
239
+ #: ../settings.php:83
240
+ msgid "Immediately block IP when attempting to login with a non-existent username"
241
+ msgstr "立即锁定尝试通过不存在的用户名登入的IP"
242
+
243
+ #: ../settings.php:84
244
+ msgid "Disable automatic redirecting to the login page when /wp-admin/ is requested by an unauthorized request"
245
+ msgstr "自动重定向登入页,当/wp-admin/被未知来源所请求"
246
+
247
+ #: ../settings.php:344
248
+ msgid "Make your protection smarter!"
249
+ msgstr "使保护更加智能!"
250
+
251
+ #: ../settings.php:348
252
+ msgid "Please enable Permalinks to use this feature. Set Permalink Settings to something other than Default."
253
+ msgstr "要使用该功能,请在Wordpress设置中将固定链接设为默认值以外的格式。"
254
+
255
+ #: ../settings.php:351
256
+ msgid "Be careful when enabling this options. If you forget the custom login URL you will not be able to login."
257
+ msgstr "谨慎使用该选项,如果忘记自定义的登入页URL,之后将无法登入。"
258
+
259
+ #: ../cerber-load.php:3833 ../settings.php:394
260
+ msgid "Main Settings"
261
+ msgstr "主要设置"
262
+
263
+ #: ../settings.php:406
264
+ msgid "Help"
265
+ msgstr "帮助"
266
+
267
+ #: ../settings.php:523 ../settings.php:645
268
+ msgid "Increase lockout duration to %s hours after %s lockouts in the last %s hours"
269
+ msgstr "增加锁定时长 %s 小时,如果达到 %s 次锁定于 %s 小时内"
270
+
271
+ #: ../cerber-load.php:215
272
+ msgid "You are not allowed to log in. Ask your administrator for assistance."
273
+ msgstr "已被禁止登入。请向管理员寻求帮助。"
274
+
275
+ #: ../cerber-load.php:221
276
+ msgid "You have reached the login attempts limit. Please try again in %d minutes."
277
+ msgstr "登入次数已受限。请 %d 分钟后再试。"
278
+
279
+ #: ../cerber-load.php:240
280
+ msgid "You have only one attempt remaining."
281
+ msgid_plural "You have %d attempts remaining."
282
+ msgstr[0] "剩余 %d 次尝试机会。"
283
+
284
+ #: ../dashboard.php:680
285
+ msgid "No activity has been logged."
286
+ msgstr "没有被记录的活动。"
287
+
288
+ #: ../dashboard.php:96
289
+ msgid "Expires"
290
+ msgstr "到期"
291
+
292
+ #: ../dashboard.php:118
293
+ msgid "No lockouts at the moment. The sky is clear."
294
+ msgstr "没有被锁定的项目。天空晴好。"
295
+
296
+ #: ../dashboard.php:131
297
+ msgid "These IPs will never be locked out"
298
+ msgstr "这些IP永不被锁定"
299
+
300
+ #: ../dashboard.php:140
301
+ msgid "Your IP"
302
+ msgstr "您的IP"
303
+
304
+ #: ../cerber-load.php:3076
305
+ msgid "Last failed attempt was at %s from IP %s with user login: %s."
306
+ msgstr "最近一次失败的登入尝试在 %s 来自IP %s 登入的用户名为: %s。"
307
+
308
+ #: ../cerber-load.php:3805
309
+ msgid "Can't activate WP Cerber due to a database error."
310
+ msgstr "数据库错误,未能激活WP Cerber安全插件。"
311
+
312
+ #: ../settings.php:530 ../settings.php:652
313
+ msgid "Notify admin if the number of active lockouts above"
314
+ msgstr "通知管理员,如果激活的锁定次数超过"
315
+
316
+ #: ../settings.php:98 ../settings.php:172 ../settings.php:334
317
+ msgid "days"
318
+ msgstr "天"
319
+
320
+ #: ../dashboard.php:1160
321
+ msgid "Cerber Quick View"
322
+ msgstr "Cerber快览"
323
+
324
+ #: ../dashboard.php:114
325
+ msgid "Hint"
326
+ msgstr "提示"
327
+
328
+ #: ../dashboard.php:114
329
+ msgid "To view activity, click on the IP"
330
+ msgstr "点击IP地址,查看其活动"
331
+
332
+ #: ../dashboard.php:158 ../dashboard.php:843 ../dashboard.php:870 ../dashboard.
333
+ #: php:962
334
+ msgid "Check for activity"
335
+ msgstr "检查活动"
336
+
337
+ #: ../settings.php:82
338
+ msgid "Always block entire subnet Class C of intruders IP"
339
+ msgstr ""
340
+
341
+ #: ../settings.php:95 ../settings.php:532 ../settings.php:654
342
+ msgid "Click to send test"
343
+ msgstr "点击发送测试"
344
+
345
+ #: ../settings.php:801 ../settings.php:802
346
+ msgid "Attention! You have changed the login URL! The new login URL is"
347
+ msgstr "注意!登入页URL已改变,新的登入页URL是"
348
+
349
+ #: ../dashboard.php:1072
350
+ msgid "Comments"
351
+ msgstr "留言"
352
+
353
+ #: ../common.php:986
354
+ msgid "Update to version %s of WP Cerber"
355
+ msgstr "升级WP Cerber到%s"
356
+
357
+ #: ../cerber-load.php:3077 ../cerber-load.php:3634
358
+ msgid "View activity in dashboard"
359
+ msgstr "在控制面板中查看活动信息"
360
+
361
+ #: ../cerber-load.php:3107
362
+ msgid "Number of active lockouts"
363
+ msgstr "已激活的锁定数量"
364
+
365
+ #: ../cerber-load.php:3111
366
+ msgid "View lockouts in dashboard"
367
+ msgstr "在控制面板中查看锁定信息"
368
+
369
+ #: ../cerber-load.php:3193
370
+ msgid "This message was sent by"
371
+ msgstr "消息来自"
372
+
373
+ #: ../dashboard.php:1001 ../cerber-tools.php:43
374
+ msgid "Tools"
375
+ msgstr "工具"
376
+
377
+ #: ../cerber-tools.php:84
378
+ msgid "Export settings to the file"
379
+ msgstr "导出设置文件"
380
+
381
+ #: ../cerber-tools.php:85
382
+ msgid "When you click the button below you will get a configuration file, which you can upload on another site."
383
+ msgstr "当点击下方按钮,将得到一份设置文件,可上传到其它网站使用。"
384
+
385
+ #: ../cerber-tools.php:86
386
+ msgid "What do you want to export?"
387
+ msgstr "要导出什么?"
388
+
389
+ #: ../cerber-tools.php:89
390
+ msgid "Download file"
391
+ msgstr "下载文件"
392
+
393
+ #: ../cerber-tools.php:91
394
+ msgid "Import settings from the file"
395
+ msgstr "导入设置文件"
396
+
397
+ #: ../cerber-tools.php:92
398
+ msgid "When you click the button below, file will be uploaded and all existing settings will be overridden."
399
+ msgstr "击下方按钮后,文件将被上传并覆盖现有的设置。"
400
+
401
+ #: ../cerber-tools.php:93
402
+ msgid "Select file to import."
403
+ msgstr "选择要导入的文件。"
404
+
405
+ #: ../cerber-tools.php:93
406
+ msgid "Maximum upload file size: %s."
407
+ msgstr "文件上传最大值: %s。"
408
+
409
+ #: ../cerber-tools.php:96
410
+ msgid "What do you want to import?"
411
+ msgstr "要导入什么?"
412
+
413
+ #: ../cerber-tools.php:98
414
+ msgid "Upload file"
415
+ msgstr "上传文件"
416
+
417
+ #: ../cerber-tools.php:145
418
+ msgid "No file was uploaded or file is corrupted"
419
+ msgstr "没有文件被上传,或者文件有误"
420
+
421
+ #: ../cerber-tools.php:178
422
+ msgid "Error while updating"
423
+ msgstr "上传错误"
424
+
425
+ #: ../cerber-tools.php:181
426
+ msgid "Settings has imported successfully from"
427
+ msgstr "设置已成功导入自"
428
+
429
+ #: ../cerber-tools.php:185
430
+ msgid "Error while parsing file"
431
+ msgstr "分析文件出错"
432
+
433
+ #: ../dashboard.php:94 ../dashboard.php:653
434
+ msgid "Hostname"
435
+ msgstr "主机名"
436
+
437
+ #: ../dashboard.php:355
438
+ msgid "unknown"
439
+ msgstr "未知"
440
+
441
+ #: ../settings.php:98 ../settings.php:330
442
+ msgid "Keep records for"
443
+ msgstr "保存记录时长"
444
+
445
+ #: ../dashboard.php:1194 ../dashboard.php:1215
446
+ msgid "active"
447
+ msgstr "激活"
448
+
449
+ #: ../dashboard.php:1194
450
+ msgid "deactivate"
451
+ msgstr "取消激活"
452
+
453
+ #: ../dashboard.php:1196
454
+ msgid "not active"
455
+ msgstr "未激活"
456
+
457
+ #: ../dashboard.php:1197 ../dashboard.php:1211
458
+ msgid "disabled"
459
+ msgstr "禁用"
460
+
461
+ #: ../dashboard.php:1202
462
+ msgid "failed attempts"
463
+ msgstr "失败尝试"
464
+
465
+ #: ../dashboard.php:1202 ../dashboard.php:1203
466
+ msgid "in 24 hours"
467
+ msgstr "在24小时内"
468
+
469
+ #: ../dashboard.php:1202 ../dashboard.php:1203
470
+ msgid "view all"
471
+ msgstr "查看全部"
472
+
473
+ #: ../dashboard.php:1203
474
+ msgid "lockouts"
475
+ msgstr "锁定"
476
+
477
+ #: ../dashboard.php:1205
478
+ msgid "Lockouts at the moment"
479
+ msgstr "现有锁定"
480
+
481
+ #: ../dashboard.php:1206
482
+ msgid "Last lockout"
483
+ msgstr "最近锁定"
484
+
485
+ #: ../dashboard.php:1207 ../dashboard.php:1208 ../dashboard.php:1763
486
+ msgid "entry"
487
+ msgid_plural "entries"
488
+ msgstr[0] "条目"
489
+
490
+ #: ../dashboard.php:1478
491
+ msgid "Confused about some settings?"
492
+ msgstr "不了解如何设置?"
493
+
494
+ #: ../dashboard.php:1479
495
+ msgid "You can easily load default recommended settings using button below"
496
+ msgstr "点击下方按钮您可以轻松载入推荐值"
497
+
498
+ #: ../dashboard.php:1481
499
+ msgid "Load default settings"
500
+ msgstr "载入默认值"
501
+
502
+ #: ../dashboard.php:1489
503
+ msgid "doesn't affect Custom login URL and Access Lists"
504
+ msgstr "不影响自定义登入页URL和接入列表"
505
+
506
+ #: ../common.php:979 ../settings.php:214
507
+ msgid "New version is available"
508
+ msgstr "新版可用"
509
+
510
+ #. Name of the plugin
511
+ #: ../dashboard.php:989 ../dashboard.php:1011
512
+ msgid "WP Cerber"
513
+ msgstr ""
514
+
515
+ #: ../cerber-load.php:3051
516
+ msgid "WP Cerber notify"
517
+ msgstr "WP Cerber通知"
518
+
519
+ #: ../cerber-load.php:3073
520
+ msgid "Citadel mode is activated"
521
+ msgstr "要塞模式已激活"
522
+
523
+ #: ../cerber-load.php:3147
524
+ msgid "New Custom login URL"
525
+ msgstr "自定义登入页URL"
526
+
527
+ #: ../cerber-load.php:3792
528
+ msgid "The WP Cerber requires PHP %s or higher. You are running"
529
+ msgstr "WP Cerber安全插件需要PHP版本不低于 %s。您运行的版本"
530
+
531
+ #: ../cerber-load.php:3796
532
+ msgid "The WP Cerber requires WordPress %s or higher. You are running"
533
+ msgstr "WP Cerber安全插件需要WordPress版本不低于 %s。您运行的版本"
534
+
535
+ #: ../settings.php:101
536
+ msgid "Use file"
537
+ msgstr "使用文件"
538
+
539
+ #: ../settings.php:101
540
+ msgid "Write failed login attempts to the file"
541
+ msgstr "将失败的登入记录到文件"
542
+
543
+ #: ../dashboard.php:1591
544
+ msgid "Deactivate"
545
+ msgstr "取消激活"
546
+
547
+ #: ../dashboard.php:97 ../cerber-load.php:3109
548
+ msgid "Reason"
549
+ msgstr "原因"
550
+
551
+ #: ../dashboard.php:170
552
+ msgid "Add IP to the list"
553
+ msgstr "添加IP到列表"
554
+
555
+ #: ../dashboard.php:889
556
+ msgid "Add IP to the Black List"
557
+ msgstr "添加IP到黑名单"
558
+
559
+ #: ../common.php:784
560
+ msgid "Attempt to access"
561
+ msgstr "试图接入"
562
+
563
+ #: ../common.php:783
564
+ msgid "Limit on login attempts is reached"
565
+ msgstr "登入次数已达限制值"
566
+
567
+ #: ../common.php:739 ../common.php:785
568
+ msgid "Attempt to log in with non-existent username"
569
+ msgstr "试图通过不存在的用户名登入"
570
+
571
+ #: ../cerber-load.php:3108
572
+ msgid "Last lockout was added: %s for IP %s"
573
+ msgstr "最近一次锁定添加于: %s 来自 IP %s"
574
+
575
+ #: ../cerber-load.php:3836 ../settings.php:399
576
+ msgid "Hardening"
577
+ msgstr "加固"
578
+
579
+ #: ../dashboard.php:866
580
+ msgid "Abuse email:"
581
+ msgstr "滥用邮箱:"
582
+
583
+ #: ../settings.php:201 ../settings.php:236
584
+ msgid "Email Address"
585
+ msgstr "邮箱"
586
+
587
+ #: ../settings.php:210
588
+ msgid "if empty, the admin email %s will be used"
589
+ msgstr "如果为空,将使用管理员邮箱 %s"
590
+
591
+ #: ../settings.php:104
592
+ msgid "Drill down IP"
593
+ msgstr ""
594
+
595
+ #: ../settings.php:104
596
+ msgid "Retrieve extra WHOIS information for IP"
597
+ msgstr ""
598
+
599
+ #: ../settings.php:112
600
+ msgid "Hardening WordPress"
601
+ msgstr "加固WordPress"
602
+
603
+ #: ../settings.php:113
604
+ msgid "Stop user enumeration"
605
+ msgstr "停止用户列举"
606
+
607
+ #: ../settings.php:115
608
+ msgid "Disable XML-RPC"
609
+ msgstr "禁用XML-RPC"
610
+
611
+ #: ../settings.php:115
612
+ msgid "Block access to the XML-RPC server (including Pingbacks and Trackbacks)"
613
+ msgstr "锁定接入 XML-RPC server (包括Pingbacks和Trackbacks)"
614
+
615
+ #: ../settings.php:116
616
+ msgid "Disable feeds"
617
+ msgstr "禁用feeds"
618
+
619
+ #: ../settings.php:116
620
+ msgid "Block access to the RSS, Atom and RDF feeds"
621
+ msgstr "锁定接入 RSS, Atom and RDF feeds"
622
+
623
+ #: ../settings.php:117
624
+ msgid "Disable REST API"
625
+ msgstr "禁用REST API"
626
+
627
+ #: ../settings.php:358
628
+ msgid "These settings do not affect hosts from the "
629
+ msgstr "这些设置不会影响"
630
+
631
+ #: ../settings.php:882 ../settings.php:894
632
+ msgid "<strong>ERROR</strong>: please enter a valid email address."
633
+ msgstr "<strong>错误</strong>: 请输入有效的邮箱地址。"
634
+
635
+ #: ../cerber-load.php:3139 ../cerber-load.php:3825
636
+ msgid "WP Cerber is now active and has started protecting your site"
637
+ msgstr "WP Cerber现已激活,开始保护您的网站"
638
+
639
+ #: ../dashboard.php:98
640
+ msgid "Action"
641
+ msgstr "操作"
642
+
643
+ #: ../dashboard.php:133
644
+ msgid "Nobody can log in or register from these IPs"
645
+ msgstr "这些IP不能登入或注册"
646
+
647
+ #: ../dashboard.php:196 ../dashboard.php:208
648
+ msgid "Incorrect IP address or IP range"
649
+ msgstr "错误的IP地址或范围"
650
+
651
+ #: ../dashboard.php:407 ../dashboard.php:1607
652
+ msgid "Settings saved"
653
+ msgstr "设置已保存"
654
+
655
+ #: ../dashboard.php:870
656
+ msgid "Network:"
657
+ msgstr "网络:"
658
+
659
+ #: ../dashboard.php:884
660
+ msgid "Add network to the Black List"
661
+ msgstr "添加网络到黑名单"
662
+
663
+ #: ../dashboard.php:1590
664
+ msgid "Attention! Citadel mode is now active. Nobody is able to log in."
665
+ msgstr "注意!要塞模式现已激活,所有用户都不能登入。"
666
+
667
+ #: ../dashboard.php:313 ../dashboard.php:2587 ../whois.php:221 ../whois.php:252 ..
668
+ #: /common.php:782 ../common.php:1061
669
+ msgid "Unknown"
670
+ msgstr "未知"
671
+
672
+ #. Author of the plugin
673
+ #:
674
+ msgid "Gregory"
675
+ msgstr ""
676
+
677
+ #: ../common.php:194 ../common.php:251 ../common.php:256 ../common.php:261 ..
678
+ #: /cerber-load.php:523 ../cerber-load.php:535 ../cerber-load.php:542 ../cerber-
679
+ #: load.php:763 ../cerber-load.php:979 ../cerber-load.php:985 ../cerber-load.php:
680
+ #: 990 ../cerber-load.php:995 ../cerber-load.php:1001 ../cerber-load.php:1008 ..
681
+ #: /cerber-load.php:1108 ../cerber-load.php:1245 ../settings.php:780 ../settings.
682
+ #: php:851
683
+ msgid "ERROR:"
684
+ msgstr "错误:"
685
+
686
+ #: ../cerber-load.php:552
687
+ msgid "Human verification failed. Please click the square box in the reCAPTCHA block below."
688
+ msgstr ""
689
+
690
+ #: ../cerber-load.php:775
691
+ msgid "<strong>ERROR</strong>: The password you entered for the username %s is incorrect."
692
+ msgstr "<strong>错误</strong>: 用户名%s密码不正确。"
693
+
694
+ #: ../cerber-load.php:996
695
+ msgid "Username is not allowed. Please choose another one."
696
+ msgstr "该用户名不可用,请更换用户名。"
697
+
698
+ #: ../cerber-load.php:3102
699
+ msgid "unspecified"
700
+ msgstr "未指定"
701
+
702
+ #: ../cerber-load.php:3105
703
+ msgid "Number of lockouts is increasing"
704
+ msgstr "被锁定的数量在增加"
705
+
706
+ #: ../cerber-load.php:3110
707
+ msgid "View activity for this IP"
708
+ msgstr "查看此IP活动"
709
+
710
+ #: ../cerber-load.php:3114 ../cerber-load.php:3116
711
+ msgid "A new version of WP Cerber is available to install"
712
+ msgstr "新版WP Cerber可供安装"
713
+
714
+ #: ../cerber-load.php:3115
715
+ msgid "Hi!"
716
+ msgstr ""
717
+
718
+ #: ../cerber-load.php:3118 ../cerber-load.php:3129
719
+ msgid "Website"
720
+ msgstr ""
721
+
722
+ #: ../cerber-load.php:3121 ../cerber-load.php:3122
723
+ msgid "The WP Cerber security plugin has been deactivated"
724
+ msgstr "WP Cerber安全插件已取消激活"
725
+
726
+ #: ../cerber-load.php:3124
727
+ msgid "Not logged in"
728
+ msgstr "未登入"
729
+
730
+ #: ../cerber-load.php:3130
731
+ msgid "By user"
732
+ msgstr "来源用户"
733
+
734
+ #: ../cerber-load.php:3131
735
+ msgid "From IP address"
736
+ msgstr "来源IP"
737
+
738
+ #: ../cerber-load.php:3134
739
+ msgid "From country"
740
+ msgstr "来源国家"
741
+
742
+ #: ../cerber-load.php:3138
743
+ msgid "The WP Cerber security plugin is now active"
744
+ msgstr "WP Cerber安全插件已激活"
745
+
746
+ #: ../cerber-load.php:3826
747
+ msgid "Your IP address is added to the"
748
+ msgstr "您的IP地址被加入到"
749
+
750
+ #: ../cerber-load.php:3838
751
+ msgid "Import settings"
752
+ msgstr "导入设置"
753
+
754
+ #: ../settings.php:213
755
+ msgid "Notification limit"
756
+ msgstr "通知限制"
757
+
758
+ #: ../settings.php:213
759
+ msgid "notification letters allowed per hour (0 means unlimited)"
760
+ msgstr "次邮件提醒于每小时 (0 代表不限制)"
761
+
762
+ #: ../settings.php:135
763
+ msgid "User related settings"
764
+ msgstr ""
765
+
766
+ #: ../settings.php:137
767
+ msgid "Prohibited usernames"
768
+ msgstr "屏蔽用户名"
769
+
770
+ #: ../settings.php:143
771
+ msgid "Usernames from this list are not allowed to log in or register. Any IP address, have tried to use any of these usernames, will be immediately blocked. Use comma to separate logins."
772
+ msgstr "列表中的用户名不能登入或注册。任何试图使用这些用户名的IP将被立即锁定。使用逗号分隔多个值。"
773
+
774
+ #: ../settings.php:145
775
+ msgid "User session expire"
776
+ msgstr "用户线程过期于"
777
+
778
+ #: ../settings.php:145
779
+ msgid "in minutes (leave empty to use default WP value)"
780
+ msgstr "分钟内(留空使用Wordpress缺省值)"
781
+
782
+ #: ../settings.php:175
783
+ msgid "reCAPTCHA settings"
784
+ msgstr ""
785
+
786
+ #: ../settings.php:176
787
+ msgid "Site key"
788
+ msgstr ""
789
+
790
+ #: ../settings.php:177
791
+ msgid "Secret key"
792
+ msgstr ""
793
+
794
+ #: ../settings.php:180
795
+ msgid "Enable reCAPTCHA for WordPress registration form"
796
+ msgstr ""
797
+
798
+ #: ../settings.php:183
799
+ msgid "Lost password form"
800
+ msgstr ""
801
+
802
+ #: ../settings.php:186
803
+ msgid "Login form"
804
+ msgstr ""
805
+
806
+ #: ../settings.php:186
807
+ msgid "Enable reCAPTCHA for WordPress login form"
808
+ msgstr ""
809
+
810
+ #: ../settings.php:361
811
+ msgid "Before you can start using reCAPTCHA, you have to obtain Site key and Secret key on the Google website"
812
+ msgstr ""
813
+
814
+ #: ../cerber-lab.php:709 ../settings.php:362
815
+ msgid "Know more"
816
+ msgstr "了解更多"
817
+
818
+ #: ../dashboard.php:989 ../settings.php:381
819
+ msgid "WP Cerber Security"
820
+ msgstr "WP Cerber安全"
821
+
822
+ #: ../settings.php:401
823
+ msgid "Users"
824
+ msgstr "用户"
825
+
826
+ #: ../common.php:706
827
+ msgid "User created"
828
+ msgstr "用户创建"
829
+
830
+ #: ../dashboard.php:1430 ../common.php:707
831
+ msgid "User registered"
832
+ msgstr "用户注册"
833
+
834
+ #: ../common.php:734
835
+ msgid "reCAPTCHA verification failed"
836
+ msgstr ""
837
+
838
+ #: ../common.php:735
839
+ msgid "reCAPTCHA settings are incorrect"
840
+ msgstr ""
841
+
842
+ #: ../common.php:738
843
+ msgid "Attempt to access prohibited URL"
844
+ msgstr "试图通过被屏蔽URL接入"
845
+
846
+ #: ../common.php:740 ../common.php:786
847
+ msgid "Attempt to log in with prohibited username"
848
+ msgstr "试图通过被屏蔽用户名登入"
849
+
850
+ #: ../settings.php:99
851
+ msgid "Cerber Lab connection"
852
+ msgstr ""
853
+
854
+ #: ../settings.php:99
855
+ msgid "Send malicious IP addresses to the Cerber Lab"
856
+ msgstr "向Cerber Lab发送恶意IP地址"
857
+
858
+ #: ../settings.php:100
859
+ msgid "Cerber Lab protocol"
860
+ msgstr ""
861
+
862
+ #: ../settings.php:155 ../settings.php:180
863
+ msgid "Registration form"
864
+ msgstr ""
865
+
866
+ #: ../settings.php:181
867
+ msgid "Enable reCAPTCHA for WooCommerce registration form"
868
+ msgstr ""
869
+
870
+ #: ../settings.php:183
871
+ msgid "Enable reCAPTCHA for WordPress lost password form"
872
+ msgstr ""
873
+
874
+ #: ../settings.php:184
875
+ msgid "Enable reCAPTCHA for WooCommerce lost password form"
876
+ msgstr ""
877
+
878
+ #: ../settings.php:187
879
+ msgid "Enable reCAPTCHA for WooCommerce login form"
880
+ msgstr ""
881
+
882
+ #: ../common.php:736
883
+ msgid "Request to the Google reCAPTCHA service failed"
884
+ msgstr ""
885
+
886
+ #: ../dashboard.php:1422 ../dashboard.php:1452
887
+ msgid "View all"
888
+ msgstr "查看全部"
889
+
890
+ #: ../dashboard.php:1453
891
+ msgid "Recently locked out IP addresses"
892
+ msgstr "最近被锁定的IP地址"
893
+
894
+ #: ../cerber-lab.php:707
895
+ msgid "OK, nail them all"
896
+ msgstr "允许"
897
+
898
+ #: ../cerber-lab.php:708
899
+ msgid "NO, maybe later"
900
+ msgstr "现在不"
901
+
902
+ #: ../dashboard.php:991 ../dashboard.php:1226 ../dashboard.php:1783 ../settings.
903
+ #: php:386
904
+ msgid "Dashboard"
905
+ msgstr "控制面板"
906
+
907
+ #: ../cerber-lab.php:705
908
+ msgid "Want to make WP Cerber even more powerful?"
909
+ msgstr ""
910
+
911
+ #: ../cerber-lab.php:706
912
+ msgid "Allow WP Cerber to send locked out malicious IP addresses to Cerber Lab. This helps the plugin team to develop new algorithms for WP Cerber that will defend WordPress against new threats and botnets that are appearing everyday. You can disable the sending in the plugin settings at any time."
913
+ msgstr "允许向Cerber Lab发送恶意IP地址。可以随时更改此项设置。"
914
+
915
+ #: ../dashboard.php:491
916
+ msgid "IP address"
917
+ msgstr "IP地址"
918
+
919
+ #: ../dashboard.php:491
920
+ msgid "User login"
921
+ msgstr "用户登入"
922
+
923
+ #: ../dashboard.php:491
924
+ msgid "User ID"
925
+ msgstr "用户ID"
926
+
927
+ #: ../dashboard.php:676
928
+ msgid "Export"
929
+ msgstr "导出"
930
+
931
+ #: ../dashboard.php:695
932
+ msgid "Search for IP or username"
933
+ msgstr "搜索IP或用户名"
934
+
935
+ #: ../dashboard.php:695
936
+ msgid "Filter"
937
+ msgstr "过滤"
938
+
939
+ #: ../dashboard.php:991
940
+ msgid "Cerber Dashboard"
941
+ msgstr "Cerber控制面板"
942
+
943
+ #: ../dashboard.php:1001
944
+ msgid "Cerber tools"
945
+ msgstr "Cerber工具"
946
+
947
+ #: ../dashboard.php:1693
948
+ msgid "Subscribe"
949
+ msgstr "订阅"
950
+
951
+ #: ../dashboard.php:1694 ../cerber-tools.php:266
952
+ msgid "Unsubscribe"
953
+ msgstr "取消订阅"
954
+
955
+ #: ../dashboard.php:1722
956
+ msgid "You've subscribed"
957
+ msgstr "您已订阅"
958
+
959
+ #: ../dashboard.php:1725
960
+ msgid "You've unsubscribed"
961
+ msgstr "您未订阅"
962
+
963
+ #: ../cerber-load.php:3151 ../cerber-load.php:3152
964
+ msgid "A new activity has been recorded"
965
+ msgstr "新活动被记录"
966
+
967
+ #: ../cerber-load.php:3606
968
+ msgid "User"
969
+ msgstr "用户"
970
+
971
+ #: ../cerber-load.php:3614
972
+ msgid "Search string"
973
+ msgstr "搜索字符串"
974
+
975
+ #: ../cerber-load.php:3635
976
+ msgid "To unsubscribe click here"
977
+ msgstr "取消订阅请点击这里"
978
+
979
+ #: ../settings.php:103
980
+ msgid "Preferences"
981
+ msgstr "参数"
982
+
983
+ #: ../settings.php:105
984
+ msgid "Date format"
985
+ msgstr "日期格式"
986
+
987
+ #: ../settings.php:105
988
+ msgid "if empty, the default format %s will be used"
989
+ msgstr "如果留空,默认格式 %s 将被使用"
990
+
991
+ #: ../settings.php:219
992
+ msgid "Push notifications"
993
+ msgstr "推送通知"
994
+
995
+ #: ../settings.php:198
996
+ msgid "Email notifications"
997
+ msgstr "邮件提醒"
998
+
999
+ #: ../settings.php:205 ../settings.php:241 ../settings.php:298
1000
+ msgid "Use comma to specify multiple values"
1001
+ msgstr "使用逗号(,)定义多个值"
1002
+
1003
+ #: ../settings.php:226
1004
+ msgid "All connected devices"
1005
+ msgstr "全部已连接设备"
1006
+
1007
+ #: ../settings.php:227
1008
+ msgid "No devices found"
1009
+ msgstr "未找到设备"
1010
+
1011
+ #: ../settings.php:229
1012
+ msgid "Not available"
1013
+ msgstr "不可用"
1014
+
1015
+ #: ../common.php:732
1016
+ msgid "Password reset requested"
1017
+ msgstr "密码重置请求"
1018
+
1019
+ #: ../common.php:787
1020
+ msgid "Limit on failed reCAPTCHA verifications is reached"
1021
+ msgstr ""
1022
+
1023
+ #: ../common.php:845
1024
+ msgid "%s ago"
1025
+ msgstr "%s之前"
1026
+
1027
+ #: ../settings.php:77
1028
+ msgid "Apply limit login rules to IP addresses in the White IP Access List"
1029
+ msgstr "IP白名单中的IP也使用限制规则"
1030
+
1031
+ #: ../settings.php:86
1032
+ msgid "Display 404 page"
1033
+ msgstr "显示404页面"
1034
+
1035
+ #: ../settings.php:178
1036
+ msgid "Invisible reCAPTCHA"
1037
+ msgstr ""
1038
+
1039
+ #: ../settings.php:178
1040
+ msgid "Enable invisible reCAPTCHA"
1041
+ msgstr ""
1042
+
1043
+ #: ../settings.php:178
1044
+ msgid "(do not enable it unless you get and enter the Site and Secret keys for the invisible version)"
1045
+ msgstr ""
1046
+
1047
+ #: ../settings.php:189
1048
+ msgid "Enable reCAPTCHA for WordPress comment form"
1049
+ msgstr ""
1050
+
1051
+ #: ../settings.php:190
1052
+ msgid "Disable reCAPTCHA for logged in users"
1053
+ msgstr ""
1054
+
1055
+ #: ../settings.php:192
1056
+ msgid "Limit attempts"
1057
+ msgstr "限制尝试"
1058
+
1059
+ #: ../settings.php:192
1060
+ msgid "Lock out IP address for %s minutes after %s failed attempts within %s minutes"
1061
+ msgstr "锁定IP时长 %s 分钟, %s 次错误尝试在 %s 分钟内"
1062
+
1063
+ #: ../settings.php:355
1064
+ msgid "In the Citadel mode nobody is able to log in except IPs from the White IP Access List. Active user sessions will not be affected."
1065
+ msgstr "要塞模式下,除了白名单中的IP,不允许登入。处于激活状态的用户线程不受影响。"
1066
+
1067
+ #: ../dashboard.php:491 ../dashboard.php:656
1068
+ msgid "Event"
1069
+ msgstr ""
1070
+
1071
+ #: ../common.php:137
1072
+ msgid "Spam comments denied"
1073
+ msgstr ""
1074
+
1075
+ #: ../common.php:139
1076
+ msgid "Malicious IP addresses detected"
1077
+ msgstr ""
1078
+
1079
+ #: ../common.php:140
1080
+ msgid "Lockouts occurred"
1081
+ msgstr ""
1082
+
1083
+ #: ../dashboard.php:1431
1084
+ msgid "All suspicious activity"
1085
+ msgstr ""
1086
+
1087
+ #: ../cerber-load.php:980 ../cerber-load.php:986 ../cerber-load.php:1002 ..
1088
+ #: /cerber-load.php:1009
1089
+ msgid "You are not allowed to register."
1090
+ msgstr ""
1091
+
1092
+ #: ../common.php:717
1093
+ msgid "Spam comment denied"
1094
+ msgstr ""
1095
+
1096
+ #: ../common.php:742
1097
+ msgid "Attempt to log in denied"
1098
+ msgstr ""
1099
+
1100
+ #: ../common.php:743
1101
+ msgid "Attempt to register denied"
1102
+ msgstr ""
1103
+
1104
+ #: ../common.php:134
1105
+ msgid "Malicious activities mitigated"
1106
+ msgstr ""
1107
+
1108
+ #: ../dashboard.php:1000
1109
+ msgid "Cerber antispam settings"
1110
+ msgstr ""
1111
+
1112
+ #: ../dashboard.php:1000 ../dashboard.php:1229 ../cerber-load.php:3835 ..
1113
+ #: /settings.php:189
1114
+ msgid "Antispam"
1115
+ msgstr ""
1116
+
1117
+ #: ../settings.php:153
1118
+ msgid "Cerber antispam engine"
1119
+ msgstr ""
1120
+
1121
+ #: ../settings.php:154
1122
+ msgid "Comment form"
1123
+ msgstr ""
1124
+
1125
+ #: ../settings.php:154
1126
+ msgid "Protect comment form with bot detection engine"
1127
+ msgstr ""
1128
+
1129
+ #: ../settings.php:155
1130
+ msgid "Protect registration form with bot detection engine"
1131
+ msgstr ""
1132
+
1133
+ #: ../cerber-tools.php:48
1134
+ msgid "Export & Import"
1135
+ msgstr ""
1136
+
1137
+ #: ../cerber-tools.php:49
1138
+ msgid "Diagnostic"
1139
+ msgstr ""
1140
+
1141
+ #: ../cerber-tools.php:50
1142
+ msgid "License"
1143
+ msgstr ""
1144
+
1145
+ #: ../cerber-tools.php:336
1146
+ msgid "Antispam and bot detection settings"
1147
+ msgstr ""
1148
+
1149
+ #: ../cerber-load.php:1245
1150
+ msgid "Sorry, human verification failed."
1151
+ msgstr ""
1152
+
1153
+ #: ../common.php:788
1154
+ msgid "Bot activity is detected"
1155
+ msgstr ""
1156
+
1157
+ #: ../settings.php:170
1158
+ msgid "Comment processing"
1159
+ msgstr ""
1160
+
1161
+ #: ../settings.php:171
1162
+ msgid "If a spam comment detected"
1163
+ msgstr ""
1164
+
1165
+ #: ../settings.php:172
1166
+ msgid "Trash spam comments"
1167
+ msgstr ""
1168
+
1169
+ #: ../settings.php:172
1170
+ msgid "Move spam comments to trash after"
1171
+ msgstr ""
1172
+
1173
+ #: ../common.php:718
1174
+ msgid "Spam form submission denied"
1175
+ msgstr ""
1176
+
1177
+ #: ../settings.php:156
1178
+ msgid "Other forms"
1179
+ msgstr ""
1180
+
1181
+ #: ../settings.php:156
1182
+ msgid "Protect all forms on the website with bot detection engine"
1183
+ msgstr ""
1184
+
1185
+ #: ../settings.php:158
1186
+ msgid "Adjust antispam engine"
1187
+ msgstr ""
1188
+
1189
+ #: ../settings.php:159
1190
+ msgid "Safe mode"
1191
+ msgstr ""
1192
+
1193
+ #: ../settings.php:159
1194
+ msgid "Use less restrictive policies (allow AJAX)"
1195
+ msgstr ""
1196
+
1197
+ #: ../dashboard.php:2854 ../settings.php:160
1198
+ msgid "Logged in users"
1199
+ msgstr ""
1200
+
1201
+ #: ../settings.php:160
1202
+ msgid "Disable bot detection engine for logged in users"
1203
+ msgstr ""
1204
+
1205
+ #. Name of the plugin
1206
+ #:
1207
+ msgid "WP Cerber Security & Antispam"
1208
+ msgstr ""
1209
+
1210
+ #: ../dashboard.php:95 ../dashboard.php:654
1211
+ msgid "Country"
1212
+ msgstr ""
1213
+
1214
+ #: ../dashboard.php:686
1215
+ msgid "All events"
1216
+ msgstr ""
1217
+
1218
+ #: ../dashboard.php:997
1219
+ msgid "Cerber Security Rules"
1220
+ msgstr ""
1221
+
1222
+ #: ../dashboard.php:997 ../dashboard.php:2168
1223
+ msgid "Security Rules"
1224
+ msgstr ""
1225
+
1226
+ #: ../dashboard.php:1074
1227
+ msgid "Failed login attempts"
1228
+ msgstr ""
1229
+
1230
+ #: ../dashboard.php:956 ../dashboard.php:1075
1231
+ msgid "Registered"
1232
+ msgstr ""
1233
+
1234
+ #: ../dashboard.php:1142
1235
+ msgid "You"
1236
+ msgstr ""
1237
+
1238
+ #: ../common.php:138
1239
+ msgid "Spam form submissions denied"
1240
+ msgstr ""
1241
+
1242
+ #: ../dashboard.php:1490 ../cerber-load.php:3141 ../cerber-load.php:3828
1243
+ msgid "Getting Started Guide"
1244
+ msgstr ""
1245
+
1246
+ #: ../dashboard.php:2173
1247
+ msgid "Countries"
1248
+ msgstr ""
1249
+
1250
+ #: ../dashboard.php:2236
1251
+ msgid "Permitted for one country"
1252
+ msgid_plural "Permitted for %d countries"
1253
+ msgstr[0] ""
1254
+
1255
+ #: ../dashboard.php:2247
1256
+ msgid "No rule"
1257
+ msgstr ""
1258
+
1259
+ #: ../dashboard.php:2459
1260
+ msgid "Security rules have been updated"
1261
+ msgstr ""
1262
+
1263
+ #. URI of the plugin
1264
+ #:
1265
+ msgid "https://wpcerber.com"
1266
+ msgstr ""
1267
+
1268
+ #: ../common.php:719
1269
+ msgid "Form submission denied"
1270
+ msgstr ""
1271
+
1272
+ #: ../common.php:720
1273
+ msgid "Comment denied"
1274
+ msgstr ""
1275
+
1276
+ #: ../common.php:746
1277
+ msgid "Request to REST API denied"
1278
+ msgstr ""
1279
+
1280
+ #: ../common.php:747
1281
+ msgid "XML-RPC request denied"
1282
+ msgstr ""
1283
+
1284
+ #: ../common.php:751
1285
+ msgid "Bot detected"
1286
+ msgstr ""
1287
+
1288
+ #: ../common.php:752
1289
+ msgid "Citadel mode is active"
1290
+ msgstr ""
1291
+
1292
+ #: ../common.php:757
1293
+ msgid "Malicious activity detected"
1294
+ msgstr ""
1295
+
1296
+ #: ../common.php:758
1297
+ msgid "Blocked by country rule"
1298
+ msgstr ""
1299
+
1300
+ #: ../common.php:759
1301
+ msgid "Limit reached"
1302
+ msgstr ""
1303
+
1304
+ #: ../common.php:760
1305
+ msgid "Multiple suspicious activities"
1306
+ msgstr ""
1307
+
1308
+ #: ../common.php:789
1309
+ msgid "Multiple suspicious activities were detected"
1310
+ msgstr ""
1311
+
1312
+ #: ../settings.php:113
1313
+ msgid "Block access to user pages like /?author=n and user data via REST API"
1314
+ msgstr ""
1315
+
1316
+ #: ../settings.php:117
1317
+ msgid "Block access to the WordPress REST API except the following"
1318
+ msgstr ""
1319
+
1320
+ #: ../settings.php:118
1321
+ msgid "Allow REST API for logged in users"
1322
+ msgstr ""
1323
+
1324
+ #: ../settings.php:125
1325
+ msgid "Specify REST API namespaces to be allowed if REST API is disabled. One string per line."
1326
+ msgstr ""
1327
+
1328
+ #: ../settings.php:136
1329
+ msgid "Registration limit"
1330
+ msgstr ""
1331
+
1332
+ #: ../settings.php:146
1333
+ msgid "Sort users in dashboard"
1334
+ msgstr ""
1335
+
1336
+ #: ../settings.php:146
1337
+ msgid "by date of registration"
1338
+ msgstr "注册日期"
1339
+
1340
+ #: ../settings.php:161
1341
+ msgid "Query whitelist"
1342
+ msgstr ""
1343
+
1344
+ #: ../settings.php:518 ../settings.php:640
1345
+ msgid "%s allowed registrations in %s minutes from one IP"
1346
+ msgstr ""
1347
+
1348
+ #: ../dashboard.php:2303
1349
+ msgid "Start typing here to find a country"
1350
+ msgstr ""
1351
+
1352
+ #: ../dashboard.php:2386
1353
+ msgid "Click on a country name to add it to the list of selected countries"
1354
+ msgstr ""
1355
+
1356
+ #: ../dashboard.php:2410
1357
+ msgid "Submit forms"
1358
+ msgstr ""
1359
+
1360
+ #: ../dashboard.php:2411
1361
+ msgid "Post comments"
1362
+ msgstr ""
1363
+
1364
+ #: ../dashboard.php:2412
1365
+ msgid "Log in to the website"
1366
+ msgstr ""
1367
+
1368
+ #: ../dashboard.php:2413
1369
+ msgid "Register on the website"
1370
+ msgstr ""
1371
+
1372
+ #: ../dashboard.php:2414
1373
+ msgid "Use XML-RPC"
1374
+ msgstr ""
1375
+
1376
+ #: ../dashboard.php:2415
1377
+ msgid "Use REST API"
1378
+ msgstr ""
1379
+
1380
+ #: ../settings.php:171
1381
+ msgid "Deny it completely"
1382
+ msgstr ""
1383
+
1384
+ #: ../settings.php:171
1385
+ msgid "Mark it as spam"
1386
+ msgstr ""
1387
+
1388
+ #: ../dashboard.php:1416
1389
+ msgid "in the last 24 hours"
1390
+ msgstr ""
1391
+
1392
+ #: ../dashboard.php:1784
1393
+ msgid "Main settings"
1394
+ msgstr ""
1395
+
1396
+ #: ../settings.php:233
1397
+ msgid "Weekly reports"
1398
+ msgstr ""
1399
+
1400
+ #: ../settings.php:737
1401
+ msgid "Sunday"
1402
+ msgstr ""
1403
+
1404
+ #: ../settings.php:738
1405
+ msgid "Monday"
1406
+ msgstr ""
1407
+
1408
+ #: ../settings.php:739
1409
+ msgid "Tuesday"
1410
+ msgstr ""
1411
+
1412
+ #: ../settings.php:740
1413
+ msgid "Wednesday"
1414
+ msgstr ""
1415
+
1416
+ #: ../settings.php:741
1417
+ msgid "Thursday"
1418
+ msgstr ""
1419
+
1420
+ #: ../settings.php:742
1421
+ msgid "Friday"
1422
+ msgstr ""
1423
+
1424
+ #: ../settings.php:743
1425
+ msgid "Saturday"
1426
+ msgstr ""
1427
+
1428
+ #: ../settings.php:803 ../settings.php:804
1429
+ msgid "If you use a caching plugin, you have to add your new login URL to the list of pages not to cache."
1430
+ msgstr ""
1431
+
1432
+ #. translators: preposition of time
1433
+ #: ../settings.php:753
1434
+ msgctxt "preposition of time"
1435
+ msgid "at"
1436
+ msgstr ""
1437
+
1438
+ #: ../cerber-load.php:3157
1439
+ msgid "Weekly report"
1440
+ msgstr ""
1441
+
1442
+ #: ../cerber-load.php:3160
1443
+ msgid "To change reporting settings visit"
1444
+ msgstr ""
1445
+
1446
+ #: ../cerber-load.php:3186
1447
+ msgid "Your login page:"
1448
+ msgstr ""
1449
+
1450
+ #: ../cerber-load.php:3190
1451
+ msgid "Your license is valid until"
1452
+ msgstr ""
1453
+
1454
+ #: ../cerber-load.php:3301
1455
+ msgid "Activity details"
1456
+ msgstr ""
1457
+
1458
+ #: ../settings.php:769
1459
+ msgid "Click to send now"
1460
+ msgstr ""
1461
+
1462
+ #: ../cerber-load.php:642
1463
+ msgid "> > > Translator of WP Cerber? To get the PRO license for free, drop your contacts here: https://wpcerber.com/contact/"
1464
+ msgstr ""
1465
+
1466
+ #: ../dashboard.php:380
1467
+ msgid "Email has been sent to"
1468
+ msgstr ""
1469
+
1470
+ #: ../dashboard.php:383
1471
+ msgid "Unable to send email to"
1472
+ msgstr ""
1473
+
1474
+ #: ../dashboard.php:2239
1475
+ msgid "Not permitted for one country"
1476
+ msgid_plural "Not permitted for %d countries"
1477
+ msgstr[0] ""
1478
+
1479
+ #: ../dashboard.php:2390
1480
+ msgctxt "to is a marker of infinitive, e.g. \"to use it\""
1481
+ msgid "Selected countries are permitted to %s, other countries are not permitted to"
1482
+ msgstr ""
1483
+
1484
+ #: ../dashboard.php:2393
1485
+ msgctxt "to is a marker of infinitive, e.g. \"to use it\""
1486
+ msgid "Selected countries are not permitted to %s, other countries are permitted to"
1487
+ msgstr ""
1488
+
1489
+ #. Description of the plugin
1490
+ #:
1491
+ msgid "Protects site from brute force attacks, bots and hackers. Antispam protection with the Cerber antispam engine and reCAPTCHA. Comprehensive control of user activity. Restrict login by IP access lists. Limit login attempts. Know more: <a href=\"https://wpcerber.com\">wpcerber.com</a>."
1492
+ msgstr ""
1493
+
1494
+ #: ../cerber-load.php:3289
1495
+ msgid "Weekly Report"
1496
+ msgstr ""
1497
+
1498
+ #: ../settings.php:86
1499
+ msgid "Use 404 template from the active theme"
1500
+ msgstr ""
1501
+
1502
+ #: ../settings.php:86
1503
+ msgid "Display simple 404 page"
1504
+ msgstr ""
1505
+
1506
+ #: ../settings.php:167
1507
+ msgid "Enter a part of query string or query path to exclude a request from inspection by the engine. One item per line."
1508
+ msgstr ""
1509
+
1510
+ #: ../settings.php:246
1511
+ msgid "if empty, email from notification settings will be used"
1512
+ msgstr ""
1513
+
1514
+ #: ../settings.php:234
1515
+ msgid "Enable reporting"
1516
+ msgstr ""
1517
+
1518
+ #: ../cerber-load.php:3214
1519
+ msgid "Your last sign-in was %s from %s"
1520
+ msgstr ""
1521
+
1522
+ #: ../cerber-load.php:3315
1523
+ msgid "Attempts to log in with non-existent username"
1524
+ msgstr ""
1525
+
1526
+ #: ../dashboard.php:169
1527
+ msgid "IP address, IPv4 address range or subnet"
1528
+ msgstr ""
1529
+
1530
+ #: ../dashboard.php:171
1531
+ msgid "Optional comment for this entry"
1532
+ msgstr ""
1533
+
1534
+ #: ../dashboard.php:212
1535
+ msgid "You cannot add your IP address or network"
1536
+ msgstr ""
1537
+
1538
+ #: ../cerber-news.php:159
1539
+ msgid "Cool!"
1540
+ msgstr ""
1541
+
1542
+ #: ../settings.php:143
1543
+ msgid "To specify a REGEX pattern wrap a pattern in two forward slashes."
1544
+ msgstr ""
1545
+
1546
+ #: ../dashboard.php:993
1547
+ msgid "Cerber Traffic Inspector"
1548
+ msgstr ""
1549
+
1550
+ #: ../dashboard.php:993 ../dashboard.php:1212 ../dashboard.php:2508
1551
+ msgid "Traffic Inspector"
1552
+ msgstr ""
1553
+
1554
+ #: ../dashboard.php:1228
1555
+ msgid "Traffic"
1556
+ msgstr ""
1557
+
1558
+ #: ../dashboard.php:2513
1559
+ msgid "Live traffic"
1560
+ msgstr ""
1561
+
1562
+ #: ../dashboard.php:2825
1563
+ msgid "Request"
1564
+ msgstr ""
1565
+
1566
+ #: ../dashboard.php:2827
1567
+ msgid "Host Info"
1568
+ msgstr ""
1569
+
1570
+ #: ../dashboard.php:2828
1571
+ msgid "User Agent"
1572
+ msgstr ""
1573
+
1574
+ #: ../dashboard.php:2853
1575
+ msgid "All requests"
1576
+ msgstr ""
1577
+
1578
+ #: ../dashboard.php:2855
1579
+ msgid "Not logged in visitors"
1580
+ msgstr ""
1581
+
1582
+ #: ../dashboard.php:2856
1583
+ msgid "Form submissions"
1584
+ msgstr ""
1585
+
1586
+ #: ../dashboard.php:2857
1587
+ msgid "Page Not Found"
1588
+ msgstr ""
1589
+
1590
+ #: ../dashboard.php:2858
1591
+ msgid "REST API"
1592
+ msgstr ""
1593
+
1594
+ #: ../dashboard.php:2859
1595
+ msgid "XML-RPC"
1596
+ msgstr ""
1597
+
1598
+ #: ../dashboard.php:2863
1599
+ msgid "Longer than"
1600
+ msgstr ""
1601
+
1602
+ #: ../dashboard.php:2876
1603
+ msgid "Refresh"
1604
+ msgstr ""
1605
+
1606
+ #: ../common.php:101
1607
+ msgid "Check for requests"
1608
+ msgstr ""
1609
+
1610
+ #: ../common.php:1005
1611
+ msgid "Not specified"
1612
+ msgstr ""
1613
+
1614
+ #: ../settings.php:270
1615
+ msgid "Logging mode"
1616
+ msgstr ""
1617
+
1618
+ #: ../settings.php:276
1619
+ msgid "Logging disabled"
1620
+ msgstr ""
1621
+
1622
+ #: ../settings.php:277
1623
+ msgid "Smart"
1624
+ msgstr ""
1625
+
1626
+ #: ../settings.php:278
1627
+ msgid "All traffic"
1628
+ msgstr ""
1629
+
1630
+ #: ../settings.php:282
1631
+ msgid "Ignore crawlers"
1632
+ msgstr ""
1633
+
1634
+ #: ../settings.php:292
1635
+ msgid "Mask these form fields"
1636
+ msgstr ""
1637
+
1638
+ #: ../settings.php:327
1639
+ msgid "milliseconds"
1640
+ msgstr ""
1641
+
1642
+ #: ../settings.php:254
1643
+ msgid "Inspection"
1644
+ msgstr ""
1645
+
1646
+ #: ../settings.php:255
1647
+ msgid "Enable traffic inspection"
1648
+ msgstr ""
1649
+
1650
+ #: ../settings.php:269
1651
+ msgid "Logging"
1652
+ msgstr ""
1653
+
1654
+ #: ../settings.php:287
1655
+ msgid "Save request fields"
1656
+ msgstr ""
1657
+
1658
+ #: ../settings.php:322
1659
+ msgid "Page generation time threshold"
1660
+ msgstr ""
1661
+
1662
+ #: ../dashboard.php:2845
1663
+ msgid "No requests have been logged."
1664
+ msgstr ""
1665
+
1666
+ #: ../dashboard.php:1211
1667
+ msgid "enabled"
1668
+ msgstr ""
1669
+
1670
+ #: ../dashboard.php:1215
1671
+ msgid "no connection"
1672
+ msgstr ""
1673
+
1674
+ #: ../dashboard.php:3130
1675
+ msgid "Advanced search"
1676
+ msgstr ""
1677
+
1678
+ #: ../dashboard.php:949
1679
+ msgid "Last seen"
1680
+ msgstr ""
1681
+
1682
+ #: ../common.php:744 ../common.php:790
1683
+ msgid "Probing for vulnerable PHP code"
1684
+ msgstr ""
1685
+
1686
+ #: ../dashboard.php:3111
1687
+ msgid "Any"
1688
+ msgstr ""
1689
+
1690
+ #: ../cerber-load.php:2941
1691
+ msgid "We're sorry, you are not allowed to proceed"
1692
+ msgstr ""
1693
+
1694
+ #: ../settings.php:260
1695
+ msgid "Request whitelist"
1696
+ msgstr ""
1697
+
1698
+ #: ../settings.php:266
1699
+ msgid "Enter a request URI to exclude the request from inspection. One item per line."
1700
+ msgstr ""
1701
+
1702
+ #: ../settings.php:303
1703
+ msgid "Save request headers"
1704
+ msgstr ""
1705
+
1706
+ #: ../settings.php:309
1707
+ msgid "Save $_SERVER"
1708
+ msgstr ""
1709
+
1710
+ #: ../settings.php:315
1711
+ msgid "Save request cookies"
1712
+ msgstr ""
1713
+
1714
+ #: ../settings.php:114
1715
+ msgid "Protect admin scripts"
1716
+ msgstr ""
1717
+
1718
+ #: ../settings.php:114
1719
+ msgid "Block unauthorized access to load-scripts.php and load-styles.php"
1720
+ msgstr ""
1721
+
1722
+ #: ../common.php:1382
1723
+ msgid "Unable to create the directory"
1724
+ msgstr ""
1725
+
1726
+ #: ../common.php:1387
1727
+ msgid "Destination folder access denied"
1728
+ msgstr ""
1729
+
1730
+ #: ../common.php:1390
1731
+ msgid "File not found"
1732
+ msgstr ""
1733
+
1734
+ #: ../common.php:1393
1735
+ msgid "Unable to copy the file"
1736
+ msgstr ""
1737
+
1738
+ #: ../common.php:1399
1739
+ msgid "Unable to delete the file"
1740
+ msgstr ""
1741
+
1742
+ #: ../settings.php:70
1743
+ msgid "Plugin initialization"
1744
+ msgstr ""
1745
+
1746
+ #: ../settings.php:71
1747
+ msgid "Load security engine"
1748
+ msgstr ""
1749
+
1750
+ #: ../settings.php:71
1751
+ msgid "Legacy mode"
1752
+ msgstr ""
1753
+
1754
+ #: ../settings.php:71
1755
+ msgid "Standard mode"
1756
+ msgstr ""
1757
+
1758
+ #: ../settings.php:781
1759
+ msgid "Plugin initialization mode has not been changed"
1760
+ msgstr ""
1761
+
1762
+ #. Name of the plugin
1763
+ #:
1764
+ msgid "WP Cerber boot module"
1765
+ msgstr ""
1766
+
1767
+ #. Description of the plugin
1768
+ #:
1769
+ msgid "This is a standard boot module for WP Cerber Security & Antispam plugin. It was installed when you set the plugin initialization mode to Standard. Know more: <a href=\"https://wpcerber.com\">wpcerber.com</a>."
1770
+ msgstr ""
1771
+
languages/wp-cerber.pot CHANGED
@@ -5,7 +5,7 @@ msgstr ""
5
  "Project-Id-Version: WP Cerber\n"
6
  "Report-Msgid-Bugs-To: \n"
7
  "POT-Creation-Date: Tue Sep 08 2015 21:38:11 GMT+0300\n"
8
- "POT-Revision-Date: Wed Feb 07 2018 15:39:47 GMT+0300\n"
9
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
10
  "Last-Translator: \n"
11
  "Language-Team: \n"
@@ -28,16 +28,16 @@ msgstr ""
28
  msgid "Remove"
29
  msgstr ""
30
 
31
- #: ../dashboard.php:93 ../dashboard.php:652 ../dashboard.php:2820 ../wp-cerber.
32
- #: php:3593
33
  msgid "IP"
34
  msgstr ""
35
 
36
- #: ../dashboard.php:94 ../dashboard.php:653
37
  msgid "Hostname"
38
  msgstr ""
39
 
40
- #: ../dashboard.php:95 ../dashboard.php:654
41
  msgid "Country"
42
  msgstr ""
43
 
@@ -45,7 +45,7 @@ msgstr ""
45
  msgid "Expires"
46
  msgstr ""
47
 
48
- #: ../dashboard.php:97 ../wp-cerber.php:3097
49
  msgid "Reason"
50
  msgstr ""
51
 
@@ -70,9 +70,9 @@ msgstr ""
70
  msgid "No lockouts at the moment. The sky is clear."
71
  msgstr ""
72
 
73
- #: ../dashboard.php:131 ../dashboard.php:627 ../dashboard.php:830 ../dashboard.
74
- #: php:1207 ../dashboard.php:2651 ../wp-cerber.php:3812 ../settings.php:74 ..
75
- #: /settings.php:351
76
  msgid "White IP Access List"
77
  msgstr ""
78
 
@@ -80,8 +80,8 @@ msgstr ""
80
  msgid "These IPs will never be locked out"
81
  msgstr ""
82
 
83
- #: ../dashboard.php:133 ../dashboard.php:628 ../dashboard.php:833 ../dashboard.
84
- #: php:1208 ../dashboard.php:2652
85
  msgid "Black IP Access List"
86
  msgstr ""
87
 
@@ -93,8 +93,8 @@ msgstr ""
93
  msgid "Your IP"
94
  msgstr ""
95
 
96
- #: ../dashboard.php:158 ../dashboard.php:843 ../dashboard.php:870 ../dashboard.
97
- #: php:962
98
  msgid "Check for activity"
99
  msgstr ""
100
 
@@ -132,8 +132,8 @@ msgstr ""
132
  msgid "Address %s was added to Black IP Access List"
133
  msgstr ""
134
 
135
- #: ../dashboard.php:313 ../dashboard.php:2581 ../whois.php:221 ../whois.php:252 ..
136
- #: /common.php:781 ../common.php:1060
137
  msgid "Unknown"
138
  msgstr ""
139
 
@@ -149,449 +149,449 @@ msgstr ""
149
  msgid "Unable to send email to"
150
  msgstr ""
151
 
152
- #: ../dashboard.php:390
153
  #, php-format
154
  msgid "Lockout for %s was removed"
155
  msgstr ""
156
 
157
- #: ../dashboard.php:407 ../dashboard.php:1607
158
  msgid "Settings saved"
159
  msgstr ""
160
 
161
- #: ../dashboard.php:491
162
  msgid "IP address"
163
  msgstr ""
164
 
165
- #: ../dashboard.php:491 ../dashboard.php:655 ../dashboard.php:2818
166
  msgid "Date"
167
  msgstr ""
168
 
169
- #: ../dashboard.php:491 ../dashboard.php:656
170
  msgid "Event"
171
  msgstr ""
172
 
173
- #: ../dashboard.php:491 ../dashboard.php:657 ../dashboard.php:2823
174
  msgid "Local User"
175
  msgstr ""
176
 
177
- #: ../dashboard.php:491
178
  msgid "User login"
179
  msgstr ""
180
 
181
- #: ../dashboard.php:491
182
  msgid "User ID"
183
  msgstr ""
184
 
185
- #: ../dashboard.php:491 ../dashboard.php:658 ../wp-cerber.php:3601
186
  msgid "Username used"
187
  msgstr ""
188
 
189
- #: ../dashboard.php:632 ../dashboard.php:836 ../dashboard.php:2656 ../common.php:
190
- #: 752
191
  msgid "Locked out"
192
  msgstr ""
193
 
194
- #: ../dashboard.php:676
195
  msgid "Export"
196
  msgstr ""
197
 
198
- #: ../dashboard.php:680
199
  msgid "No activity has been logged."
200
  msgstr ""
201
 
202
- #: ../dashboard.php:686
203
  msgid "All events"
204
  msgstr ""
205
 
206
- #: ../dashboard.php:695
207
  msgid "Search for IP or username"
208
  msgstr ""
209
 
210
- #: ../dashboard.php:695
211
  msgid "Filter"
212
  msgstr ""
213
 
214
- #: ../dashboard.php:866
215
  msgid "Abuse email:"
216
  msgstr ""
217
 
218
- #: ../dashboard.php:870
219
  msgid "Network:"
220
  msgstr ""
221
 
222
- #: ../dashboard.php:884
223
  msgid "Add network to the Black List"
224
  msgstr ""
225
 
226
- #: ../dashboard.php:889
227
  msgid "Add IP to the Black List"
228
  msgstr ""
229
 
230
- #: ../dashboard.php:949
231
  msgid "Last seen"
232
  msgstr ""
233
 
234
- #: ../dashboard.php:956 ../dashboard.php:1075
235
  msgid "Registered"
236
  msgstr ""
237
 
238
- #: ../dashboard.php:989 ../settings.php:374
239
  msgid "WP Cerber Security"
240
  msgstr ""
241
 
242
  #. Name of the plugin
243
- #: ../dashboard.php:989 ../dashboard.php:1011
244
  msgid "WP Cerber"
245
  msgstr ""
246
 
247
- #: ../dashboard.php:991
248
  msgid "Cerber Dashboard"
249
  msgstr ""
250
 
251
- #: ../dashboard.php:991 ../dashboard.php:1226 ../dashboard.php:1783 ../settings.
252
- #: php:379
253
  msgid "Dashboard"
254
  msgstr ""
255
 
256
- #: ../dashboard.php:993
257
  msgid "Cerber Traffic Inspector"
258
  msgstr ""
259
 
260
- #: ../dashboard.php:993 ../dashboard.php:1212 ../dashboard.php:2502
261
  msgid "Traffic Inspector"
262
  msgstr ""
263
 
264
- #: ../dashboard.php:997
265
  msgid "Cerber Security Rules"
266
  msgstr ""
267
 
268
- #: ../dashboard.php:997 ../dashboard.php:2162
269
  msgid "Security Rules"
270
  msgstr ""
271
 
272
- #: ../dashboard.php:1000
273
  msgid "Cerber antispam settings"
274
  msgstr ""
275
 
276
- #: ../dashboard.php:1000 ../dashboard.php:1229 ../wp-cerber.php:3821 ../settings.
277
- #: php:186
278
  msgid "Antispam"
279
  msgstr ""
280
 
281
- #: ../dashboard.php:1001
282
  msgid "Cerber tools"
283
  msgstr ""
284
 
285
- #: ../dashboard.php:1001 ../cerber-tools.php:43
286
  msgid "Tools"
287
  msgstr ""
288
 
289
- #: ../dashboard.php:1072
290
  msgid "Comments"
291
  msgstr ""
292
 
293
- #: ../dashboard.php:1073
294
  msgid "Last login"
295
  msgstr ""
296
 
297
- #: ../dashboard.php:1074
298
  msgid "Failed login attempts"
299
  msgstr ""
300
 
301
- #: ../dashboard.php:1106 ../dashboard.php:1190
302
  msgid "Never"
303
  msgstr ""
304
 
305
- #: ../dashboard.php:1142
306
  msgid "You"
307
  msgstr ""
308
 
309
- #: ../dashboard.php:1160
310
  msgid "Cerber Quick View"
311
  msgstr ""
312
 
313
- #: ../dashboard.php:1194 ../dashboard.php:1215
314
  msgid "active"
315
  msgstr ""
316
 
317
- #: ../dashboard.php:1194
318
  msgid "deactivate"
319
  msgstr ""
320
 
321
- #: ../dashboard.php:1196
322
  msgid "not active"
323
  msgstr ""
324
 
325
- #: ../dashboard.php:1197 ../dashboard.php:1211
326
  msgid "disabled"
327
  msgstr ""
328
 
329
- #: ../dashboard.php:1202
330
  msgid "failed attempts"
331
  msgstr ""
332
 
333
- #: ../dashboard.php:1202 ../dashboard.php:1203
334
  msgid "in 24 hours"
335
  msgstr ""
336
 
337
- #: ../dashboard.php:1202 ../dashboard.php:1203
338
  msgid "view all"
339
  msgstr ""
340
 
341
- #: ../dashboard.php:1203
342
  msgid "lockouts"
343
  msgstr ""
344
 
345
- #: ../dashboard.php:1205
346
  msgid "Lockouts at the moment"
347
  msgstr ""
348
 
349
- #: ../dashboard.php:1206
350
  msgid "Last lockout"
351
  msgstr ""
352
 
353
- #: ../dashboard.php:1207 ../dashboard.php:1208 ../dashboard.php:1763
354
  msgid "entry"
355
  msgid_plural "entries"
356
  msgstr[0] ""
357
  msgstr[1] ""
358
 
359
- #: ../dashboard.php:1209 ../settings.php:89
360
  msgid "Citadel mode"
361
  msgstr ""
362
 
363
- #: ../dashboard.php:1211
364
  msgid "enabled"
365
  msgstr ""
366
 
367
- #: ../dashboard.php:1215
368
  msgid "no connection"
369
  msgstr ""
370
 
371
- #: ../dashboard.php:1227 ../dashboard.php:1437 ../wp-cerber.php:3584 ../settings.
372
- #: php:94 ../settings.php:381
373
  msgid "Activity"
374
  msgstr ""
375
 
376
- #: ../dashboard.php:1228
377
  msgid "Traffic"
378
  msgstr ""
379
 
380
- #: ../dashboard.php:1284 ../settings.php:76
381
  msgid "My site is behind a reverse proxy"
382
  msgstr ""
383
 
384
- #: ../dashboard.php:1416
385
  msgid "in the last 24 hours"
386
  msgstr ""
387
 
388
- #: ../dashboard.php:1422 ../dashboard.php:1452
389
  msgid "View all"
390
  msgstr ""
391
 
392
- #: ../dashboard.php:1430 ../common.php:706
393
  msgid "User registered"
394
  msgstr ""
395
 
396
- #: ../dashboard.php:1431
397
  msgid "All suspicious activity"
398
  msgstr ""
399
 
400
- #: ../dashboard.php:1453
401
  msgid "Recently locked out IP addresses"
402
  msgstr ""
403
 
404
- #: ../dashboard.php:1478
405
  msgid "Confused about some settings?"
406
  msgstr ""
407
 
408
- #: ../dashboard.php:1479
409
  msgid "You can easily load default recommended settings using button below"
410
  msgstr ""
411
 
412
- #: ../dashboard.php:1481
413
  msgid "Load default settings"
414
  msgstr ""
415
 
416
- #: ../dashboard.php:1483
417
  msgid "Are you sure?"
418
  msgstr ""
419
 
420
- #: ../dashboard.php:1489
421
  msgid "doesn't affect Custom login URL and Access Lists"
422
  msgstr ""
423
 
424
- #: ../dashboard.php:1490 ../wp-cerber.php:3129 ../wp-cerber.php:3814
425
  msgid "Getting Started Guide"
426
  msgstr ""
427
 
428
- #: ../dashboard.php:1590
429
  msgid "Attention! Citadel mode is now active. Nobody is able to log in."
430
  msgstr ""
431
 
432
- #: ../dashboard.php:1591
433
  msgid "Deactivate"
434
  msgstr ""
435
 
436
- #: ../dashboard.php:1592
437
  msgid "View Activity"
438
  msgstr ""
439
 
440
- #: ../dashboard.php:1693
441
  msgid "Subscribe"
442
  msgstr ""
443
 
444
- #: ../dashboard.php:1694 ../cerber-tools.php:266
445
  msgid "Unsubscribe"
446
  msgstr ""
447
 
448
- #: ../dashboard.php:1722
449
  msgid "You've subscribed"
450
  msgstr ""
451
 
452
- #: ../dashboard.php:1725
453
  msgid "You've unsubscribed"
454
  msgstr ""
455
 
456
- #: ../dashboard.php:1784
457
  msgid "Main settings"
458
  msgstr ""
459
 
460
- #: ../dashboard.php:2167
461
  msgid "Countries"
462
  msgstr ""
463
 
464
- #: ../dashboard.php:2230
465
  #, php-format
466
  msgid "Permitted for one country"
467
  msgid_plural "Permitted for %d countries"
468
  msgstr[0] ""
469
  msgstr[1] ""
470
 
471
- #: ../dashboard.php:2233
472
  #, php-format
473
  msgid "Not permitted for one country"
474
  msgid_plural "Not permitted for %d countries"
475
  msgstr[0] ""
476
  msgstr[1] ""
477
 
478
- #: ../dashboard.php:2241
479
  msgid "No rule"
480
  msgstr ""
481
 
482
- #: ../dashboard.php:2297
483
  msgid "Start typing here to find a country"
484
  msgstr ""
485
 
486
- #: ../dashboard.php:2380
487
  msgid "Click on a country name to add it to the list of selected countries"
488
  msgstr ""
489
 
490
- #: ../dashboard.php:2384
491
  #, php-format
492
  msgctxt "to is a marker of infinitive, e.g. \"to use it\""
493
  msgid "Selected countries are permitted to %s, other countries are not permitted to"
494
  msgstr ""
495
 
496
- #: ../dashboard.php:2387
497
  #, php-format
498
  msgctxt "to is a marker of infinitive, e.g. \"to use it\""
499
  msgid "Selected countries are not permitted to %s, other countries are permitted to"
500
  msgstr ""
501
 
502
- #: ../dashboard.php:2404
503
  msgid "Submit forms"
504
  msgstr ""
505
 
506
- #: ../dashboard.php:2405
507
  msgid "Post comments"
508
  msgstr ""
509
 
510
- #: ../dashboard.php:2406
511
  msgid "Log in to the website"
512
  msgstr ""
513
 
514
- #: ../dashboard.php:2407
515
  msgid "Register on the website"
516
  msgstr ""
517
 
518
- #: ../dashboard.php:2408
519
  msgid "Use XML-RPC"
520
  msgstr ""
521
 
522
- #: ../dashboard.php:2409
523
  msgid "Use REST API"
524
  msgstr ""
525
 
526
- #: ../dashboard.php:2453
527
  msgid "Security rules have been updated"
528
  msgstr ""
529
 
530
- #: ../dashboard.php:2507
531
  msgid "Live traffic"
532
  msgstr ""
533
 
534
- #: ../dashboard.php:2508 ../cerber-tools.php:87 ../cerber-tools.php:96
535
  msgid "Settings"
536
  msgstr ""
537
 
538
- #: ../dashboard.php:2819
539
  msgid "Request"
540
  msgstr ""
541
 
542
- #: ../dashboard.php:2821
543
  msgid "Host Info"
544
  msgstr ""
545
 
546
- #: ../dashboard.php:2822
547
  msgid "User Agent"
548
  msgstr ""
549
 
550
- #: ../dashboard.php:2839
551
  msgid "No requests have been logged."
552
  msgstr ""
553
 
554
- #: ../dashboard.php:2847
555
  msgid "All requests"
556
  msgstr ""
557
 
558
- #: ../dashboard.php:2848 ../settings.php:157
559
  msgid "Logged in users"
560
  msgstr ""
561
 
562
- #: ../dashboard.php:2849
563
  msgid "Not logged in visitors"
564
  msgstr ""
565
 
566
- #: ../dashboard.php:2850
567
  msgid "Form submissions"
568
  msgstr ""
569
 
570
- #: ../dashboard.php:2851
571
  msgid "Page Not Found"
572
  msgstr ""
573
 
574
- #: ../dashboard.php:2852
575
  msgid "REST API"
576
  msgstr ""
577
 
578
- #: ../dashboard.php:2853
579
  msgid "XML-RPC"
580
  msgstr ""
581
 
582
- #: ../dashboard.php:2857
583
  msgid "Longer than"
584
  msgstr ""
585
 
586
- #: ../dashboard.php:2870
587
  msgid "Refresh"
588
  msgstr ""
589
 
590
- #: ../dashboard.php:3105
591
  msgid "Any"
592
  msgstr ""
593
 
594
- #: ../dashboard.php:3124
595
  msgid "Advanced search"
596
  msgstr ""
597
 
@@ -615,1112 +615,1162 @@ msgstr ""
615
  msgid "Gregory"
616
  msgstr ""
617
 
618
- #: ../wp-cerber.php:238
619
- msgid "You are not allowed to log in. Ask your administrator for assistance."
620
  msgstr ""
621
 
622
- #: ../wp-cerber.php:244
623
- #, php-format
624
- msgid "You have reached the login attempts limit. Please try again in %d minutes."
625
  msgstr ""
626
 
627
- #: ../wp-cerber.php:263
628
- #, php-format
629
- msgid "You have only one attempt remaining."
630
- msgid_plural "You have %d attempts remaining."
631
- msgstr[0] ""
632
- msgstr[1] ""
633
-
634
- #: ../wp-cerber.php:546 ../wp-cerber.php:558 ../wp-cerber.php:565 ../wp-cerber.
635
- #: php:761 ../wp-cerber.php:977 ../wp-cerber.php:983 ../wp-cerber.php:988 ../wp-
636
- #: cerber.php:993 ../wp-cerber.php:999 ../wp-cerber.php:1006 ../wp-cerber.php:
637
- #: 1106 ../wp-cerber.php:1243 ../common.php:194 ../common.php:251 ../common.php:
638
- #: 255 ../settings.php:837
639
- msgid "ERROR:"
640
  msgstr ""
641
 
642
- #: ../wp-cerber.php:575
643
- msgid ""
644
- "Human verification failed. Please click the square box in the reCAPTCHA "
645
- "block below."
646
  msgstr ""
647
 
648
- #: ../wp-cerber.php:640
649
- msgid ""
650
- "> > > Translator of WP Cerber? To get the PRO license for free, drop your "
651
- "contacts here: https://wpcerber.com/contact/"
652
  msgstr ""
653
 
654
- #: ../wp-cerber.php:773
655
- #, php-format
656
- msgid ""
657
- "<strong>ERROR</strong>: The password you entered for the username %s is "
658
- "incorrect."
659
  msgstr ""
660
 
661
- #: ../wp-cerber.php:978 ../wp-cerber.php:984 ../wp-cerber.php:1000 ../wp-cerber.
662
- #: php:1007
663
- msgid "You are not allowed to register."
 
 
 
 
664
  msgstr ""
665
 
666
- #: ../wp-cerber.php:994
667
- msgid "Username is not allowed. Please choose another one."
668
  msgstr ""
669
 
670
- #: ../wp-cerber.php:1243
671
- msgid "Sorry, human verification failed."
672
  msgstr ""
673
 
674
- #: ../wp-cerber.php:2929
675
- msgid "We're sorry, you are not allowed to proceed"
676
  msgstr ""
677
 
678
- #: ../wp-cerber.php:3039
679
- msgid "WP Cerber notify"
680
  msgstr ""
681
 
682
- #: ../wp-cerber.php:3061
683
- msgid "Citadel mode is activated"
684
  msgstr ""
685
 
686
- #: ../wp-cerber.php:3063
687
- #, php-format
688
- msgid "Citadel mode is activated after %d failed login attempts in %d minutes."
689
  msgstr ""
690
 
691
- #: ../wp-cerber.php:3064
692
- #, php-format
693
- msgid "Last failed attempt was at %s from IP %s with user login: %s."
694
  msgstr ""
695
 
696
- #: ../wp-cerber.php:3065 ../wp-cerber.php:3625
697
- msgid "View activity in dashboard"
698
  msgstr ""
699
 
700
- #: ../wp-cerber.php:3090
701
- msgid "unspecified"
702
  msgstr ""
703
 
704
- #: ../wp-cerber.php:3093
705
- msgid "Number of lockouts is increasing"
706
  msgstr ""
707
 
708
- #: ../wp-cerber.php:3095
709
- msgid "Number of active lockouts"
710
  msgstr ""
711
 
712
- #: ../wp-cerber.php:3096
713
- #, php-format
714
- msgid "Last lockout was added: %s for IP %s"
715
  msgstr ""
716
 
717
- #: ../wp-cerber.php:3098
718
- msgid "View activity for this IP"
719
  msgstr ""
720
 
721
- #: ../wp-cerber.php:3099
722
- msgid "View lockouts in dashboard"
723
  msgstr ""
724
 
725
- #: ../wp-cerber.php:3102 ../wp-cerber.php:3104
726
- msgid "A new version of WP Cerber is available to install"
727
  msgstr ""
728
 
729
- #: ../wp-cerber.php:3103
730
- msgid "Hi!"
731
  msgstr ""
732
 
733
- #: ../wp-cerber.php:3106 ../wp-cerber.php:3117
734
- msgid "Website"
735
  msgstr ""
736
 
737
- #: ../wp-cerber.php:3109 ../wp-cerber.php:3110
738
- msgid "The WP Cerber security plugin has been deactivated"
739
  msgstr ""
740
 
741
- #: ../wp-cerber.php:3112
742
- msgid "Not logged in"
743
  msgstr ""
744
 
745
- #: ../wp-cerber.php:3118
746
- msgid "By user"
747
  msgstr ""
748
 
749
- #: ../wp-cerber.php:3119
750
- msgid "From IP address"
751
  msgstr ""
752
 
753
- #: ../wp-cerber.php:3122
754
- msgid "From country"
755
  msgstr ""
756
 
757
- #: ../wp-cerber.php:3126
758
- msgid "The WP Cerber security plugin is now active"
759
  msgstr ""
760
 
761
- #: ../wp-cerber.php:3127 ../wp-cerber.php:3811
762
- msgid "WP Cerber is now active and has started protecting your site"
763
  msgstr ""
764
 
765
- #: ../wp-cerber.php:3135
766
- msgid "New Custom login URL"
767
  msgstr ""
768
 
769
- #: ../wp-cerber.php:3139 ../wp-cerber.php:3140
770
- msgid "A new activity has been recorded"
771
  msgstr ""
772
 
773
- #: ../wp-cerber.php:3145
774
- msgid "Weekly report"
775
  msgstr ""
776
 
777
- #: ../wp-cerber.php:3148
778
- msgid "To change reporting settings visit"
779
  msgstr ""
780
 
781
- #: ../wp-cerber.php:3174
782
- msgid "Your login page:"
783
  msgstr ""
784
 
785
- #: ../wp-cerber.php:3178
786
- msgid "Your license is valid until"
787
  msgstr ""
788
 
789
- #: ../wp-cerber.php:3181
790
- msgid "This message was sent by"
791
  msgstr ""
792
 
793
- #: ../wp-cerber.php:3202
794
- #, php-format
795
- msgid "Your last sign-in was %s from %s"
796
  msgstr ""
797
 
798
- #: ../wp-cerber.php:3277
799
- msgid "Weekly Report"
800
  msgstr ""
801
 
802
- #: ../wp-cerber.php:3289
803
- msgid "Activity details"
804
  msgstr ""
805
 
806
- #: ../wp-cerber.php:3303
807
- msgid "Attempts to log in with non-existent username"
808
  msgstr ""
809
 
810
- #: ../wp-cerber.php:3597
811
- msgid "User"
812
  msgstr ""
813
 
814
- #: ../wp-cerber.php:3605
815
- msgid "Search string"
816
  msgstr ""
817
 
818
- #: ../wp-cerber.php:3626
819
- msgid "To unsubscribe click here"
820
  msgstr ""
821
 
822
- #: ../wp-cerber.php:3782
823
  #, php-format
824
- msgid "The WP Cerber requires PHP %s or higher. You are running"
825
  msgstr ""
826
 
827
- #: ../wp-cerber.php:3786
 
 
 
 
828
  #, php-format
829
- msgid "The WP Cerber requires WordPress %s or higher. You are running"
830
  msgstr ""
831
 
832
- #: ../wp-cerber.php:3795
833
- msgid "Can't activate WP Cerber due to a database error."
834
  msgstr ""
835
 
836
- #: ../wp-cerber.php:3812
837
- msgid "Your IP address is added to the"
838
  msgstr ""
839
 
840
- #: ../wp-cerber.php:3819 ../settings.php:387
841
- msgid "Main Settings"
842
  msgstr ""
843
 
844
- #: ../wp-cerber.php:3820 ../settings.php:390 ../cerber-tools.php:88 ../cerber-
845
- #: tools.php:97 ../cerber-tools.php:178
846
- msgid "Access Lists"
847
  msgstr ""
848
 
849
- #: ../wp-cerber.php:3822 ../settings.php:392
850
- msgid "Hardening"
851
  msgstr ""
852
 
853
- #: ../wp-cerber.php:3823 ../settings.php:75 ../settings.php:92 ../settings.php:397
854
- msgid "Notifications"
855
  msgstr ""
856
 
857
- #: ../wp-cerber.php:3824
858
- msgid "Import settings"
859
  msgstr ""
860
 
861
- #: ../common.php:101
862
- msgid "Check for requests"
863
  msgstr ""
864
 
865
- #: ../common.php:134
866
- msgid "Malicious activities mitigated"
 
 
 
 
867
  msgstr ""
868
 
869
- #: ../common.php:137
870
- msgid "Spam comments denied"
871
  msgstr ""
872
 
873
- #: ../common.php:138
874
- msgid "Spam form submissions denied"
875
  msgstr ""
876
 
877
- #: ../common.php:139
878
- msgid "Malicious IP addresses detected"
879
  msgstr ""
880
 
881
- #: ../common.php:140
882
- msgid "Lockouts occurred"
883
  msgstr ""
884
 
885
- #: ../common.php:705
886
- msgid "User created"
 
887
  msgstr ""
888
 
889
- #: ../common.php:707
890
- msgid "Logged in"
 
 
 
 
 
 
 
 
 
891
  msgstr ""
892
 
893
- #: ../common.php:708
894
- msgid "Logged out"
 
 
895
  msgstr ""
896
 
897
- #: ../common.php:709
898
- msgid "Login failed"
 
 
 
899
  msgstr ""
900
 
901
- #: ../common.php:712
902
- msgid "IP blocked"
 
903
  msgstr ""
904
 
905
- #: ../common.php:713
906
- msgid "Subnet blocked"
907
  msgstr ""
908
 
909
- #: ../common.php:715
910
- msgid "Citadel activated!"
911
  msgstr ""
912
 
913
- #: ../common.php:716
914
- msgid "Spam comment denied"
915
  msgstr ""
916
 
917
- #: ../common.php:717
918
- msgid "Spam form submission denied"
919
  msgstr ""
920
 
921
- #: ../common.php:718
922
- msgid "Form submission denied"
923
  msgstr ""
924
 
925
- #: ../common.php:719
926
- msgid "Comment denied"
 
927
  msgstr ""
928
 
929
- #: ../common.php:730
930
- msgid "Password changed"
 
931
  msgstr ""
932
 
933
- #: ../common.php:731
934
- msgid "Password reset requested"
935
  msgstr ""
936
 
937
- #: ../common.php:733
938
- msgid "reCAPTCHA verification failed"
939
  msgstr ""
940
 
941
- #: ../common.php:734
942
- msgid "reCAPTCHA settings are incorrect"
943
  msgstr ""
944
 
945
- #: ../common.php:735
946
- msgid "Request to the Google reCAPTCHA service failed"
947
  msgstr ""
948
 
949
- #: ../common.php:737
950
- msgid "Attempt to access prohibited URL"
 
951
  msgstr ""
952
 
953
- #: ../common.php:738 ../common.php:784
954
- msgid "Attempt to log in with non-existent username"
955
  msgstr ""
956
 
957
- #: ../common.php:739 ../common.php:785
958
- msgid "Attempt to log in with prohibited username"
959
  msgstr ""
960
 
961
- #: ../common.php:741
962
- msgid "Attempt to log in denied"
963
  msgstr ""
964
 
965
- #: ../common.php:742
966
- msgid "Attempt to register denied"
967
  msgstr ""
968
 
969
- #: ../common.php:743 ../common.php:789
970
- msgid "Probing for vulnerable PHP code"
971
  msgstr ""
972
 
973
- #: ../common.php:745
974
- msgid "Request to REST API denied"
975
  msgstr ""
976
 
977
- #: ../common.php:746
978
- msgid "XML-RPC request denied"
979
  msgstr ""
980
 
981
- #: ../common.php:750
982
- msgid "Bot detected"
983
  msgstr ""
984
 
985
- #: ../common.php:751
986
- msgid "Citadel mode is active"
987
  msgstr ""
988
 
989
- #: ../common.php:753
990
- msgid "IP blacklisted"
991
  msgstr ""
992
 
993
- #: ../common.php:756
994
- msgid "Malicious activity detected"
995
  msgstr ""
996
 
997
- #: ../common.php:757
998
- msgid "Blocked by country rule"
999
  msgstr ""
1000
 
1001
- #: ../common.php:758
1002
- msgid "Limit reached"
1003
  msgstr ""
1004
 
1005
- #: ../common.php:759
1006
- msgid "Multiple suspicious activities"
1007
  msgstr ""
1008
 
1009
- #: ../common.php:782
1010
- msgid "Limit on login attempts is reached"
1011
  msgstr ""
1012
 
1013
- #: ../common.php:783
1014
- msgid "Attempt to access"
1015
  msgstr ""
1016
 
1017
- #: ../common.php:786
1018
- msgid "Limit on failed reCAPTCHA verifications is reached"
1019
  msgstr ""
1020
 
1021
- #: ../common.php:787
1022
- msgid "Bot activity is detected"
1023
  msgstr ""
1024
 
1025
- #: ../common.php:788
1026
- msgid "Multiple suspicious activities were detected"
1027
  msgstr ""
1028
 
1029
- #: ../common.php:844
1030
  #, php-format
1031
- msgid "%s ago"
1032
  msgstr ""
1033
 
1034
- #: ../common.php:978
1035
- msgid "New version is available"
 
 
 
 
1036
  msgstr ""
1037
 
1038
- #: ../common.php:985
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1039
  #, php-format
1040
- msgid "Update to version %s of WP Cerber"
1041
  msgstr ""
1042
 
1043
- #: ../common.php:1004
1044
- msgid "Not specified"
 
1045
  msgstr ""
1046
 
1047
- #: ../cerber-news.php:159
1048
- msgid "Cool!"
1049
  msgstr ""
1050
 
1051
- #: ../cerber-lab.php:705
1052
- msgid "Want to make WP Cerber even more powerful?"
1053
  msgstr ""
1054
 
1055
- #: ../cerber-lab.php:706
1056
- msgid ""
1057
- "Allow WP Cerber to send locked out malicious IP addresses to Cerber Lab. "
1058
- "This helps the plugin team to develop new algorithms for WP Cerber that will "
1059
- "defend WordPress against new threats and botnets that are appearing "
1060
- "everyday. You can disable the sending in the plugin settings at any time."
1061
  msgstr ""
1062
 
1063
- #: ../cerber-lab.php:707
1064
- msgid "OK, nail them all"
 
1065
  msgstr ""
1066
 
1067
- #: ../cerber-lab.php:708
1068
- msgid "NO, maybe later"
1069
  msgstr ""
1070
 
1071
- #: ../cerber-lab.php:709 ../settings.php:355
1072
- msgid "Know more"
 
 
 
 
 
1073
  msgstr ""
1074
 
1075
  #: ../settings.php:70
1076
- msgid "Limit login attempts"
1077
  msgstr ""
1078
 
1079
  #: ../settings.php:71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1080
  msgid "Attempts"
1081
  msgstr ""
1082
 
1083
- #: ../settings.php:72
1084
  msgid "Lockout duration"
1085
  msgstr ""
1086
 
1087
- #: ../settings.php:72 ../settings.php:91
1088
  msgid "minutes"
1089
  msgstr ""
1090
 
1091
- #: ../settings.php:73
1092
  msgid "Aggressive lockout"
1093
  msgstr ""
1094
 
1095
- #: ../settings.php:74
1096
  msgid "Apply limit login rules to IP addresses in the White IP Access List"
1097
  msgstr ""
1098
 
1099
- #: ../settings.php:76
1100
  msgid "Site connection"
1101
  msgstr ""
1102
 
1103
- #: ../settings.php:78
1104
  msgid "Proactive security rules"
1105
  msgstr ""
1106
 
1107
- #: ../settings.php:79
1108
  msgid "Block subnet"
1109
  msgstr ""
1110
 
1111
- #: ../settings.php:79
1112
  msgid "Always block entire subnet Class C of intruders IP"
1113
  msgstr ""
1114
 
1115
- #: ../settings.php:80
1116
  msgid "Non-existent users"
1117
  msgstr ""
1118
 
1119
- #: ../settings.php:80
1120
  msgid "Immediately block IP when attempting to login with a non-existent username"
1121
  msgstr ""
1122
 
1123
- #: ../settings.php:81
1124
  msgid "Redirect dashboard requests"
1125
  msgstr ""
1126
 
1127
- #: ../settings.php:81
1128
  msgid ""
1129
  "Disable automatic redirecting to the login page when /wp-admin/ is requested "
1130
  "by an unauthorized request"
1131
  msgstr ""
1132
 
1133
- #: ../settings.php:82
1134
  msgid "Request wp-login.php"
1135
  msgstr ""
1136
 
1137
- #: ../settings.php:82
1138
  msgid "Immediately block IP after any request to wp-login.php"
1139
  msgstr ""
1140
 
1141
- #: ../settings.php:83
1142
  msgid "Display 404 page"
1143
  msgstr ""
1144
 
1145
- #: ../settings.php:83
1146
  msgid "Use 404 template from the active theme"
1147
  msgstr ""
1148
 
1149
- #: ../settings.php:83
1150
  msgid "Display simple 404 page"
1151
  msgstr ""
1152
 
1153
- #: ../settings.php:85
1154
  msgid "Custom login page"
1155
  msgstr ""
1156
 
1157
- #: ../settings.php:86
1158
  msgid "Custom login URL"
1159
  msgstr ""
1160
 
1161
- #: ../settings.php:86
1162
  msgid "must not overlap with the existing pages or posts slug"
1163
  msgstr ""
1164
 
1165
- #: ../settings.php:87
1166
  msgid "Disable wp-login.php"
1167
  msgstr ""
1168
 
1169
- #: ../settings.php:87
1170
  msgid "Block direct access to wp-login.php and return HTTP 404 Not Found Error"
1171
  msgstr ""
1172
 
1173
- #: ../settings.php:90
1174
  msgid "Threshold"
1175
  msgstr ""
1176
 
1177
- #: ../settings.php:91
1178
  msgid "Duration"
1179
  msgstr ""
1180
 
1181
- #: ../settings.php:92
1182
  msgid "Send notification to admin email"
1183
  msgstr ""
1184
 
1185
- #: ../settings.php:92 ../settings.php:525 ../settings.php:647
1186
  msgid "Click to send test"
1187
  msgstr ""
1188
 
1189
- #: ../settings.php:95 ../settings.php:323
1190
  msgid "Keep records for"
1191
  msgstr ""
1192
 
1193
- #: ../settings.php:95 ../settings.php:169 ../settings.php:327
1194
  msgid "days"
1195
  msgstr ""
1196
 
1197
- #: ../settings.php:96
1198
  msgid "Cerber Lab connection"
1199
  msgstr ""
1200
 
1201
- #: ../settings.php:96
1202
  msgid "Send malicious IP addresses to the Cerber Lab"
1203
  msgstr ""
1204
 
1205
- #: ../settings.php:97
1206
  msgid "Cerber Lab protocol"
1207
  msgstr ""
1208
 
1209
- #: ../settings.php:98
1210
  msgid "Use file"
1211
  msgstr ""
1212
 
1213
- #: ../settings.php:98
1214
  msgid "Write failed login attempts to the file"
1215
  msgstr ""
1216
 
1217
- #: ../settings.php:100
1218
  msgid "Preferences"
1219
  msgstr ""
1220
 
1221
- #: ../settings.php:101
1222
  msgid "Drill down IP"
1223
  msgstr ""
1224
 
1225
- #: ../settings.php:101
1226
  msgid "Retrieve extra WHOIS information for IP"
1227
  msgstr ""
1228
 
1229
- #: ../settings.php:102
1230
  msgid "Date format"
1231
  msgstr ""
1232
 
1233
- #: ../settings.php:102
1234
  #, php-format
1235
  msgid "if empty, the default format %s will be used"
1236
  msgstr ""
1237
 
1238
- #: ../settings.php:109
1239
  msgid "Hardening WordPress"
1240
  msgstr ""
1241
 
1242
- #: ../settings.php:110
1243
  msgid "Stop user enumeration"
1244
  msgstr ""
1245
 
1246
- #: ../settings.php:110
1247
  msgid "Block access to user pages like /?author=n and user data via REST API"
1248
  msgstr ""
1249
 
1250
- #: ../settings.php:111
1251
  msgid "Protect admin scripts"
1252
  msgstr ""
1253
 
1254
- #: ../settings.php:111
1255
  msgid "Block unauthorized access to load-scripts.php and load-styles.php"
1256
  msgstr ""
1257
 
1258
- #: ../settings.php:112
1259
  msgid "Disable XML-RPC"
1260
  msgstr ""
1261
 
1262
- #: ../settings.php:112
1263
  msgid "Block access to the XML-RPC server (including Pingbacks and Trackbacks)"
1264
  msgstr ""
1265
 
1266
- #: ../settings.php:113
1267
  msgid "Disable feeds"
1268
  msgstr ""
1269
 
1270
- #: ../settings.php:113
1271
  msgid "Block access to the RSS, Atom and RDF feeds"
1272
  msgstr ""
1273
 
1274
- #: ../settings.php:114
1275
  msgid "Disable REST API"
1276
  msgstr ""
1277
 
1278
- #: ../settings.php:114
1279
  msgid "Block access to the WordPress REST API except the following"
1280
  msgstr ""
1281
 
1282
- #: ../settings.php:115
1283
  msgid "Allow REST API for logged in users"
1284
  msgstr ""
1285
 
1286
- #: ../settings.php:122
1287
  msgid ""
1288
  "Specify REST API namespaces to be allowed if REST API is disabled. One "
1289
  "string per line."
1290
  msgstr ""
1291
 
1292
- #: ../settings.php:132
1293
  msgid "User related settings"
1294
  msgstr ""
1295
 
1296
- #: ../settings.php:133
1297
  msgid "Registration limit"
1298
  msgstr ""
1299
 
1300
- #: ../settings.php:134
1301
  msgid "Prohibited usernames"
1302
  msgstr ""
1303
 
1304
- #: ../settings.php:140
1305
  msgid ""
1306
  "Usernames from this list are not allowed to log in or register. Any IP "
1307
  "address, have tried to use any of these usernames, will be immediately "
1308
  "blocked. Use comma to separate logins."
1309
  msgstr ""
1310
 
1311
- #: ../settings.php:140
1312
  msgid "To specify a REGEX pattern wrap a pattern in two forward slashes."
1313
  msgstr ""
1314
 
1315
- #: ../settings.php:142
1316
  msgid "User session expire"
1317
  msgstr ""
1318
 
1319
- #: ../settings.php:142
1320
  msgid "in minutes (leave empty to use default WP value)"
1321
  msgstr ""
1322
 
1323
- #: ../settings.php:143
1324
  msgid "Sort users in dashboard"
1325
  msgstr ""
1326
 
1327
- #: ../settings.php:143
1328
  msgid "by date of registration"
1329
  msgstr ""
1330
 
1331
- #: ../settings.php:150
1332
  msgid "Cerber antispam engine"
1333
  msgstr ""
1334
 
1335
- #: ../settings.php:151
1336
  msgid "Comment form"
1337
  msgstr ""
1338
 
1339
- #: ../settings.php:151
1340
  msgid "Protect comment form with bot detection engine"
1341
  msgstr ""
1342
 
1343
- #: ../settings.php:152 ../settings.php:177
1344
  msgid "Registration form"
1345
  msgstr ""
1346
 
1347
- #: ../settings.php:152
1348
  msgid "Protect registration form with bot detection engine"
1349
  msgstr ""
1350
 
1351
- #: ../settings.php:153
1352
  msgid "Other forms"
1353
  msgstr ""
1354
 
1355
- #: ../settings.php:153
1356
  msgid "Protect all forms on the website with bot detection engine"
1357
  msgstr ""
1358
 
1359
- #: ../settings.php:155
1360
  msgid "Adjust antispam engine"
1361
  msgstr ""
1362
 
1363
- #: ../settings.php:156
1364
  msgid "Safe mode"
1365
  msgstr ""
1366
 
1367
- #: ../settings.php:156
1368
  msgid "Use less restrictive policies (allow AJAX)"
1369
  msgstr ""
1370
 
1371
- #: ../settings.php:157
1372
  msgid "Disable bot detection engine for logged in users"
1373
  msgstr ""
1374
 
1375
- #: ../settings.php:158
1376
  msgid "Query whitelist"
1377
  msgstr ""
1378
 
1379
- #: ../settings.php:164
1380
  msgid ""
1381
  "Enter a part of query string or query path to exclude a request from "
1382
  "inspection by the engine. One item per line."
1383
  msgstr ""
1384
 
1385
- #: ../settings.php:167
1386
  msgid "Comment processing"
1387
  msgstr ""
1388
 
1389
- #: ../settings.php:168
1390
  msgid "If a spam comment detected"
1391
  msgstr ""
1392
 
1393
- #: ../settings.php:168
1394
  msgid "Deny it completely"
1395
  msgstr ""
1396
 
1397
- #: ../settings.php:168
1398
  msgid "Mark it as spam"
1399
  msgstr ""
1400
 
1401
- #: ../settings.php:169
1402
  msgid "Trash spam comments"
1403
  msgstr ""
1404
 
1405
- #: ../settings.php:169
1406
  msgid "Move spam comments to trash after"
1407
  msgstr ""
1408
 
1409
- #: ../settings.php:172
1410
  msgid "reCAPTCHA settings"
1411
  msgstr ""
1412
 
1413
- #: ../settings.php:173
1414
  msgid "Site key"
1415
  msgstr ""
1416
 
1417
- #: ../settings.php:174
1418
  msgid "Secret key"
1419
  msgstr ""
1420
 
1421
- #: ../settings.php:175
1422
  msgid "Invisible reCAPTCHA"
1423
  msgstr ""
1424
 
1425
- #: ../settings.php:175
1426
  msgid "Enable invisible reCAPTCHA"
1427
  msgstr ""
1428
 
1429
- #: ../settings.php:175
1430
  msgid ""
1431
  "(do not enable it unless you get and enter the Site and Secret keys for the "
1432
  "invisible version)"
1433
  msgstr ""
1434
 
1435
- #: ../settings.php:177
1436
  msgid "Enable reCAPTCHA for WordPress registration form"
1437
  msgstr ""
1438
 
1439
- #: ../settings.php:178
1440
  msgid "Enable reCAPTCHA for WooCommerce registration form"
1441
  msgstr ""
1442
 
1443
- #: ../settings.php:180
1444
  msgid "Lost password form"
1445
  msgstr ""
1446
 
1447
- #: ../settings.php:180
1448
  msgid "Enable reCAPTCHA for WordPress lost password form"
1449
  msgstr ""
1450
 
1451
- #: ../settings.php:181
1452
  msgid "Enable reCAPTCHA for WooCommerce lost password form"
1453
  msgstr ""
1454
 
1455
- #: ../settings.php:183
1456
  msgid "Login form"
1457
  msgstr ""
1458
 
1459
- #: ../settings.php:183
1460
  msgid "Enable reCAPTCHA for WordPress login form"
1461
  msgstr ""
1462
 
1463
- #: ../settings.php:184
1464
  msgid "Enable reCAPTCHA for WooCommerce login form"
1465
  msgstr ""
1466
 
1467
- #: ../settings.php:186
1468
  msgid "Enable reCAPTCHA for WordPress comment form"
1469
  msgstr ""
1470
 
1471
- #: ../settings.php:187
1472
  msgid "Disable reCAPTCHA for logged in users"
1473
  msgstr ""
1474
 
1475
- #: ../settings.php:189
1476
  msgid "Limit attempts"
1477
  msgstr ""
1478
 
1479
- #: ../settings.php:189
1480
  #, php-format
1481
  msgid "Lock out IP address for %s minutes after %s failed attempts within %s minutes"
1482
  msgstr ""
1483
 
1484
- #: ../settings.php:195
1485
  msgid "Email notifications"
1486
  msgstr ""
1487
 
1488
- #: ../settings.php:198 ../settings.php:229
1489
  msgid "Email Address"
1490
  msgstr ""
1491
 
1492
- #: ../settings.php:202 ../settings.php:234 ../settings.php:291
1493
  msgid "Use comma to specify multiple values"
1494
  msgstr ""
1495
 
1496
- #: ../settings.php:207
1497
  #, php-format
1498
  msgid "if empty, the admin email %s will be used"
1499
  msgstr ""
1500
 
1501
- #: ../settings.php:210
1502
  msgid "Notification limit"
1503
  msgstr ""
1504
 
1505
- #: ../settings.php:210
1506
  msgid "notification letters allowed per hour (0 means unlimited)"
1507
  msgstr ""
1508
 
1509
- #: ../settings.php:212
1510
  msgid "Push notifications"
1511
  msgstr ""
1512
 
1513
- #: ../settings.php:219
1514
  msgid "All connected devices"
1515
  msgstr ""
1516
 
1517
- #: ../settings.php:220
1518
  msgid "No devices found"
1519
  msgstr ""
1520
 
1521
- #: ../settings.php:222
1522
  msgid "Not available"
1523
  msgstr ""
1524
 
1525
- #: ../settings.php:226
1526
  msgid "Weekly reports"
1527
  msgstr ""
1528
 
1529
- #: ../settings.php:227
1530
  msgid "Enable reporting"
1531
  msgstr ""
1532
 
1533
- #: ../settings.php:239
1534
  msgid "if empty, email from notification settings will be used"
1535
  msgstr ""
1536
 
1537
- #: ../settings.php:247
1538
  msgid "Inspection"
1539
  msgstr ""
1540
 
1541
- #: ../settings.php:248
1542
  msgid "Enable traffic inspection"
1543
  msgstr ""
1544
 
1545
- #: ../settings.php:253
1546
  msgid "Request whitelist"
1547
  msgstr ""
1548
 
1549
- #: ../settings.php:259
1550
  msgid ""
1551
  "Enter a request URI to exclude the request from inspection. One item per "
1552
  "line."
1553
  msgstr ""
1554
 
1555
- #: ../settings.php:262
1556
  msgid "Logging"
1557
  msgstr ""
1558
 
1559
- #: ../settings.php:263
1560
  msgid "Logging mode"
1561
  msgstr ""
1562
 
1563
- #: ../settings.php:269
1564
  msgid "Logging disabled"
1565
  msgstr ""
1566
 
1567
- #: ../settings.php:270
1568
  msgid "Smart"
1569
  msgstr ""
1570
 
1571
- #: ../settings.php:271
1572
  msgid "All traffic"
1573
  msgstr ""
1574
 
1575
- #: ../settings.php:275
1576
  msgid "Ignore crawlers"
1577
  msgstr ""
1578
 
1579
- #: ../settings.php:280
1580
  msgid "Save request fields"
1581
  msgstr ""
1582
 
1583
- #: ../settings.php:285
1584
  msgid "Mask these form fields"
1585
  msgstr ""
1586
 
1587
- #: ../settings.php:296
1588
  msgid "Save request headers"
1589
  msgstr ""
1590
 
1591
- #: ../settings.php:302
1592
  msgid "Save $_SERVER"
1593
  msgstr ""
1594
 
1595
- #: ../settings.php:308
1596
  msgid "Save request cookies"
1597
  msgstr ""
1598
 
1599
- #: ../settings.php:315
1600
  msgid "Page generation time threshold"
1601
  msgstr ""
1602
 
1603
- #: ../settings.php:320
1604
  msgid "milliseconds"
1605
  msgstr ""
1606
 
1607
- #: ../settings.php:337
1608
  msgid "Make your protection smarter!"
1609
  msgstr ""
1610
 
1611
- #: ../settings.php:341
1612
  msgid ""
1613
  "Please enable Permalinks to use this feature. Set Permalink Settings to "
1614
  "something other than Default."
1615
  msgstr ""
1616
 
1617
- #: ../settings.php:344
1618
  msgid ""
1619
  "Be careful when enabling this options. If you forget the custom login URL "
1620
  "you will not be able to login."
1621
  msgstr ""
1622
 
1623
- #: ../settings.php:348
1624
  msgid ""
1625
  "In the Citadel mode nobody is able to log in except IPs from the White IP "
1626
  "Access List. Active user sessions will not be affected."
1627
  msgstr ""
1628
 
1629
- #: ../settings.php:351
1630
  msgid "These settings do not affect hosts from the "
1631
  msgstr ""
1632
 
1633
- #: ../settings.php:354
1634
  msgid ""
1635
  "Before you can start using reCAPTCHA, you have to obtain Site key and Secret "
1636
  "key on the Google website"
1637
  msgstr ""
1638
 
1639
- #: ../settings.php:385
1640
  msgid "Lockouts"
1641
  msgstr ""
1642
 
1643
- #: ../settings.php:394
1644
  msgid "Users"
1645
  msgstr ""
1646
 
1647
- #: ../settings.php:399
1648
  msgid "Help"
1649
  msgstr ""
1650
 
1651
- #: ../settings.php:506 ../settings.php:628
1652
  #, php-format
1653
  msgid "%s allowed retries in %s minutes"
1654
  msgstr ""
1655
 
1656
- #: ../settings.php:511 ../settings.php:633
1657
  #, php-format
1658
  msgid "%s allowed registrations in %s minutes from one IP"
1659
  msgstr ""
1660
 
1661
- #: ../settings.php:516 ../settings.php:638
1662
  #, php-format
1663
  msgid "Increase lockout duration to %s hours after %s lockouts in the last %s hours"
1664
  msgstr ""
1665
 
1666
- #: ../settings.php:523 ../settings.php:645
1667
  msgid "Notify admin if the number of active lockouts above"
1668
  msgstr ""
1669
 
1670
- #: ../settings.php:528 ../settings.php:650
1671
  #, php-format
1672
  msgid "Enable after %s failed login attempts in last %s minutes"
1673
  msgstr ""
1674
 
1675
- #: ../settings.php:730
1676
  msgid "Sunday"
1677
  msgstr ""
1678
 
1679
- #: ../settings.php:731
1680
  msgid "Monday"
1681
  msgstr ""
1682
 
1683
- #: ../settings.php:732
1684
  msgid "Tuesday"
1685
  msgstr ""
1686
 
1687
- #: ../settings.php:733
1688
  msgid "Wednesday"
1689
  msgstr ""
1690
 
1691
- #: ../settings.php:734
1692
  msgid "Thursday"
1693
  msgstr ""
1694
 
1695
- #: ../settings.php:735
1696
  msgid "Friday"
1697
  msgstr ""
1698
 
1699
- #: ../settings.php:736
1700
  msgid "Saturday"
1701
  msgstr ""
1702
 
1703
  #. translators: preposition of time
1704
- #: ../settings.php:746
1705
  msgctxt "preposition of time"
1706
  msgid "at"
1707
  msgstr ""
1708
 
1709
- #: ../settings.php:762
1710
  msgid "Click to send now"
1711
  msgstr ""
1712
 
1713
- #: ../settings.php:787 ../settings.php:788
 
 
 
 
1714
  msgid "Attention! You have changed the login URL! The new login URL is"
1715
  msgstr ""
1716
 
1717
- #: ../settings.php:789 ../settings.php:790
1718
  msgid ""
1719
  "If you use a caching plugin, you have to add your new login URL to the list "
1720
  "of pages not to cache."
1721
  msgstr ""
1722
 
1723
- #: ../settings.php:868 ../settings.php:880
1724
  msgid "<strong>ERROR</strong>: please enter a valid email address."
1725
  msgstr ""
1726
 
@@ -1797,6 +1847,17 @@ msgstr ""
1797
  msgid "Error while parsing file"
1798
  msgstr ""
1799
 
1800
- #: ../cerber-tools.php:336
1801
  msgid "Antispam and bot detection settings"
1802
  msgstr ""
 
 
 
 
 
 
 
 
 
 
 
5
  "Project-Id-Version: WP Cerber\n"
6
  "Report-Msgid-Bugs-To: \n"
7
  "POT-Creation-Date: Tue Sep 08 2015 21:38:11 GMT+0300\n"
8
+ "POT-Revision-Date: Sat Mar 17 2018 10:50:53 GMT+0300\n"
9
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
10
  "Last-Translator: \n"
11
  "Language-Team: \n"
28
  msgid "Remove"
29
  msgstr ""
30
 
31
+ #: ../dashboard.php:93 ../dashboard.php:659 ../dashboard.php:2833 ../cerber-load.
32
+ #: php:3746
33
  msgid "IP"
34
  msgstr ""
35
 
36
+ #: ../dashboard.php:94 ../dashboard.php:660
37
  msgid "Hostname"
38
  msgstr ""
39
 
40
+ #: ../dashboard.php:95 ../dashboard.php:661
41
  msgid "Country"
42
  msgstr ""
43
 
45
  msgid "Expires"
46
  msgstr ""
47
 
48
+ #: ../dashboard.php:97 ../cerber-load.php:3253
49
  msgid "Reason"
50
  msgstr ""
51
 
70
  msgid "No lockouts at the moment. The sky is clear."
71
  msgstr ""
72
 
73
+ #: ../dashboard.php:131 ../dashboard.php:634 ../dashboard.php:837 ../dashboard.
74
+ #: php:1214 ../dashboard.php:2664 ../cerber-load.php:3969 ../settings.php:77 ..
75
+ #: /settings.php:358
76
  msgid "White IP Access List"
77
  msgstr ""
78
 
80
  msgid "These IPs will never be locked out"
81
  msgstr ""
82
 
83
+ #: ../dashboard.php:133 ../dashboard.php:635 ../dashboard.php:840 ../dashboard.
84
+ #: php:1215 ../dashboard.php:2665
85
  msgid "Black IP Access List"
86
  msgstr ""
87
 
93
  msgid "Your IP"
94
  msgstr ""
95
 
96
+ #: ../dashboard.php:158 ../dashboard.php:850 ../dashboard.php:877 ../dashboard.
97
+ #: php:969
98
  msgid "Check for activity"
99
  msgstr ""
100
 
132
  msgid "Address %s was added to Black IP Access List"
133
  msgstr ""
134
 
135
+ #: ../dashboard.php:313 ../dashboard.php:2594 ../whois.php:221 ../whois.php:252 ..
136
+ #: /common.php:818 ../common.php:1097
137
  msgid "Unknown"
138
  msgstr ""
139
 
149
  msgid "Unable to send email to"
150
  msgstr ""
151
 
152
+ #: ../dashboard.php:389
153
  #, php-format
154
  msgid "Lockout for %s was removed"
155
  msgstr ""
156
 
157
+ #: ../dashboard.php:405 ../dashboard.php:1614
158
  msgid "Settings saved"
159
  msgstr ""
160
 
161
+ #: ../dashboard.php:498
162
  msgid "IP address"
163
  msgstr ""
164
 
165
+ #: ../dashboard.php:498 ../dashboard.php:662 ../dashboard.php:2831
166
  msgid "Date"
167
  msgstr ""
168
 
169
+ #: ../dashboard.php:498 ../dashboard.php:663
170
  msgid "Event"
171
  msgstr ""
172
 
173
+ #: ../dashboard.php:498 ../dashboard.php:664 ../dashboard.php:2836
174
  msgid "Local User"
175
  msgstr ""
176
 
177
+ #: ../dashboard.php:498
178
  msgid "User login"
179
  msgstr ""
180
 
181
+ #: ../dashboard.php:498
182
  msgid "User ID"
183
  msgstr ""
184
 
185
+ #: ../dashboard.php:498 ../dashboard.php:665 ../cerber-load.php:3754
186
  msgid "Username used"
187
  msgstr ""
188
 
189
+ #: ../dashboard.php:639 ../dashboard.php:843 ../dashboard.php:2669 ../common.php:
190
+ #: 789
191
  msgid "Locked out"
192
  msgstr ""
193
 
194
+ #: ../dashboard.php:683
195
  msgid "Export"
196
  msgstr ""
197
 
198
+ #: ../dashboard.php:687
199
  msgid "No activity has been logged."
200
  msgstr ""
201
 
202
+ #: ../dashboard.php:693
203
  msgid "All events"
204
  msgstr ""
205
 
206
+ #: ../dashboard.php:702
207
  msgid "Search for IP or username"
208
  msgstr ""
209
 
210
+ #: ../dashboard.php:702
211
  msgid "Filter"
212
  msgstr ""
213
 
214
+ #: ../dashboard.php:873
215
  msgid "Abuse email:"
216
  msgstr ""
217
 
218
+ #: ../dashboard.php:877
219
  msgid "Network:"
220
  msgstr ""
221
 
222
+ #: ../dashboard.php:891
223
  msgid "Add network to the Black List"
224
  msgstr ""
225
 
226
+ #: ../dashboard.php:896
227
  msgid "Add IP to the Black List"
228
  msgstr ""
229
 
230
+ #: ../dashboard.php:956
231
  msgid "Last seen"
232
  msgstr ""
233
 
234
+ #: ../dashboard.php:963 ../dashboard.php:1082
235
  msgid "Registered"
236
  msgstr ""
237
 
238
+ #: ../dashboard.php:996 ../settings.php:381
239
  msgid "WP Cerber Security"
240
  msgstr ""
241
 
242
  #. Name of the plugin
243
+ #: ../dashboard.php:996 ../dashboard.php:1018
244
  msgid "WP Cerber"
245
  msgstr ""
246
 
247
+ #: ../dashboard.php:998
248
  msgid "Cerber Dashboard"
249
  msgstr ""
250
 
251
+ #: ../dashboard.php:998 ../dashboard.php:1233 ../dashboard.php:1790 ../settings.
252
+ #: php:386
253
  msgid "Dashboard"
254
  msgstr ""
255
 
256
+ #: ../dashboard.php:1000
257
  msgid "Cerber Traffic Inspector"
258
  msgstr ""
259
 
260
+ #: ../dashboard.php:1000 ../dashboard.php:1219 ../dashboard.php:2515
261
  msgid "Traffic Inspector"
262
  msgstr ""
263
 
264
+ #: ../dashboard.php:1004
265
  msgid "Cerber Security Rules"
266
  msgstr ""
267
 
268
+ #: ../dashboard.php:1004 ../dashboard.php:2175
269
  msgid "Security Rules"
270
  msgstr ""
271
 
272
+ #: ../dashboard.php:1007
273
  msgid "Cerber antispam settings"
274
  msgstr ""
275
 
276
+ #: ../dashboard.php:1007 ../dashboard.php:1236 ../cerber-load.php:3978 ..
277
+ #: /settings.php:189
278
  msgid "Antispam"
279
  msgstr ""
280
 
281
+ #: ../dashboard.php:1008
282
  msgid "Cerber tools"
283
  msgstr ""
284
 
285
+ #: ../dashboard.php:1008 ../cerber-tools.php:43
286
  msgid "Tools"
287
  msgstr ""
288
 
289
+ #: ../dashboard.php:1079
290
  msgid "Comments"
291
  msgstr ""
292
 
293
+ #: ../dashboard.php:1080
294
  msgid "Last login"
295
  msgstr ""
296
 
297
+ #: ../dashboard.php:1081
298
  msgid "Failed login attempts"
299
  msgstr ""
300
 
301
+ #: ../dashboard.php:1113 ../dashboard.php:1197
302
  msgid "Never"
303
  msgstr ""
304
 
305
+ #: ../dashboard.php:1149
306
  msgid "You"
307
  msgstr ""
308
 
309
+ #: ../dashboard.php:1167
310
  msgid "Cerber Quick View"
311
  msgstr ""
312
 
313
+ #: ../dashboard.php:1201 ../dashboard.php:1222
314
  msgid "active"
315
  msgstr ""
316
 
317
+ #: ../dashboard.php:1201
318
  msgid "deactivate"
319
  msgstr ""
320
 
321
+ #: ../dashboard.php:1203
322
  msgid "not active"
323
  msgstr ""
324
 
325
+ #: ../dashboard.php:1204 ../dashboard.php:1218
326
  msgid "disabled"
327
  msgstr ""
328
 
329
+ #: ../dashboard.php:1209
330
  msgid "failed attempts"
331
  msgstr ""
332
 
333
+ #: ../dashboard.php:1209 ../dashboard.php:1210
334
  msgid "in 24 hours"
335
  msgstr ""
336
 
337
+ #: ../dashboard.php:1209 ../dashboard.php:1210
338
  msgid "view all"
339
  msgstr ""
340
 
341
+ #: ../dashboard.php:1210
342
  msgid "lockouts"
343
  msgstr ""
344
 
345
+ #: ../dashboard.php:1212
346
  msgid "Lockouts at the moment"
347
  msgstr ""
348
 
349
+ #: ../dashboard.php:1213
350
  msgid "Last lockout"
351
  msgstr ""
352
 
353
+ #: ../dashboard.php:1214 ../dashboard.php:1215 ../dashboard.php:1770
354
  msgid "entry"
355
  msgid_plural "entries"
356
  msgstr[0] ""
357
  msgstr[1] ""
358
 
359
+ #: ../dashboard.php:1216 ../settings.php:92
360
  msgid "Citadel mode"
361
  msgstr ""
362
 
363
+ #: ../dashboard.php:1218
364
  msgid "enabled"
365
  msgstr ""
366
 
367
+ #: ../dashboard.php:1222
368
  msgid "no connection"
369
  msgstr ""
370
 
371
+ #: ../dashboard.php:1234 ../dashboard.php:1444 ../cerber-load.php:3737 ..
372
+ #: /settings.php:97 ../settings.php:388
373
  msgid "Activity"
374
  msgstr ""
375
 
376
+ #: ../dashboard.php:1235
377
  msgid "Traffic"
378
  msgstr ""
379
 
380
+ #: ../dashboard.php:1291 ../settings.php:79
381
  msgid "My site is behind a reverse proxy"
382
  msgstr ""
383
 
384
+ #: ../dashboard.php:1423
385
  msgid "in the last 24 hours"
386
  msgstr ""
387
 
388
+ #: ../dashboard.php:1429 ../dashboard.php:1459
389
  msgid "View all"
390
  msgstr ""
391
 
392
+ #: ../dashboard.php:1437 ../common.php:741
393
  msgid "User registered"
394
  msgstr ""
395
 
396
+ #: ../dashboard.php:1438
397
  msgid "All suspicious activity"
398
  msgstr ""
399
 
400
+ #: ../dashboard.php:1460
401
  msgid "Recently locked out IP addresses"
402
  msgstr ""
403
 
404
+ #: ../dashboard.php:1485
405
  msgid "Confused about some settings?"
406
  msgstr ""
407
 
408
+ #: ../dashboard.php:1486
409
  msgid "You can easily load default recommended settings using button below"
410
  msgstr ""
411
 
412
+ #: ../dashboard.php:1488
413
  msgid "Load default settings"
414
  msgstr ""
415
 
416
+ #: ../dashboard.php:1490
417
  msgid "Are you sure?"
418
  msgstr ""
419
 
420
+ #: ../dashboard.php:1496
421
  msgid "doesn't affect Custom login URL and Access Lists"
422
  msgstr ""
423
 
424
+ #: ../dashboard.php:1497 ../cerber-load.php:3285 ../cerber-load.php:3971
425
  msgid "Getting Started Guide"
426
  msgstr ""
427
 
428
+ #: ../dashboard.php:1597
429
  msgid "Attention! Citadel mode is now active. Nobody is able to log in."
430
  msgstr ""
431
 
432
+ #: ../dashboard.php:1598
433
  msgid "Deactivate"
434
  msgstr ""
435
 
436
+ #: ../dashboard.php:1599
437
  msgid "View Activity"
438
  msgstr ""
439
 
440
+ #: ../dashboard.php:1700
441
  msgid "Subscribe"
442
  msgstr ""
443
 
444
+ #: ../dashboard.php:1701 ../cerber-tools.php:269
445
  msgid "Unsubscribe"
446
  msgstr ""
447
 
448
+ #: ../dashboard.php:1729
449
  msgid "You've subscribed"
450
  msgstr ""
451
 
452
+ #: ../dashboard.php:1732
453
  msgid "You've unsubscribed"
454
  msgstr ""
455
 
456
+ #: ../dashboard.php:1791
457
  msgid "Main settings"
458
  msgstr ""
459
 
460
+ #: ../dashboard.php:2180
461
  msgid "Countries"
462
  msgstr ""
463
 
464
+ #: ../dashboard.php:2243
465
  #, php-format
466
  msgid "Permitted for one country"
467
  msgid_plural "Permitted for %d countries"
468
  msgstr[0] ""
469
  msgstr[1] ""
470
 
471
+ #: ../dashboard.php:2246
472
  #, php-format
473
  msgid "Not permitted for one country"
474
  msgid_plural "Not permitted for %d countries"
475
  msgstr[0] ""
476
  msgstr[1] ""
477
 
478
+ #: ../dashboard.php:2254
479
  msgid "No rule"
480
  msgstr ""
481
 
482
+ #: ../dashboard.php:2310
483
  msgid "Start typing here to find a country"
484
  msgstr ""
485
 
486
+ #: ../dashboard.php:2393
487
  msgid "Click on a country name to add it to the list of selected countries"
488
  msgstr ""
489
 
490
+ #: ../dashboard.php:2397
491
  #, php-format
492
  msgctxt "to is a marker of infinitive, e.g. \"to use it\""
493
  msgid "Selected countries are permitted to %s, other countries are not permitted to"
494
  msgstr ""
495
 
496
+ #: ../dashboard.php:2400
497
  #, php-format
498
  msgctxt "to is a marker of infinitive, e.g. \"to use it\""
499
  msgid "Selected countries are not permitted to %s, other countries are permitted to"
500
  msgstr ""
501
 
502
+ #: ../dashboard.php:2417
503
  msgid "Submit forms"
504
  msgstr ""
505
 
506
+ #: ../dashboard.php:2418
507
  msgid "Post comments"
508
  msgstr ""
509
 
510
+ #: ../dashboard.php:2419
511
  msgid "Log in to the website"
512
  msgstr ""
513
 
514
+ #: ../dashboard.php:2420
515
  msgid "Register on the website"
516
  msgstr ""
517
 
518
+ #: ../dashboard.php:2421
519
  msgid "Use XML-RPC"
520
  msgstr ""
521
 
522
+ #: ../dashboard.php:2422
523
  msgid "Use REST API"
524
  msgstr ""
525
 
526
+ #: ../dashboard.php:2466
527
  msgid "Security rules have been updated"
528
  msgstr ""
529
 
530
+ #: ../dashboard.php:2520
531
  msgid "Live traffic"
532
  msgstr ""
533
 
534
+ #: ../dashboard.php:2521 ../cerber-tools.php:87 ../cerber-tools.php:96
535
  msgid "Settings"
536
  msgstr ""
537
 
538
+ #: ../dashboard.php:2832
539
  msgid "Request"
540
  msgstr ""
541
 
542
+ #: ../dashboard.php:2834
543
  msgid "Host Info"
544
  msgstr ""
545
 
546
+ #: ../dashboard.php:2835
547
  msgid "User Agent"
548
  msgstr ""
549
 
550
+ #: ../dashboard.php:2852
551
  msgid "No requests have been logged."
552
  msgstr ""
553
 
554
+ #: ../dashboard.php:2860
555
  msgid "All requests"
556
  msgstr ""
557
 
558
+ #: ../dashboard.php:2861 ../settings.php:160
559
  msgid "Logged in users"
560
  msgstr ""
561
 
562
+ #: ../dashboard.php:2862
563
  msgid "Not logged in visitors"
564
  msgstr ""
565
 
566
+ #: ../dashboard.php:2863
567
  msgid "Form submissions"
568
  msgstr ""
569
 
570
+ #: ../dashboard.php:2864
571
  msgid "Page Not Found"
572
  msgstr ""
573
 
574
+ #: ../dashboard.php:2865
575
  msgid "REST API"
576
  msgstr ""
577
 
578
+ #: ../dashboard.php:2866
579
  msgid "XML-RPC"
580
  msgstr ""
581
 
582
+ #: ../dashboard.php:2870
583
  msgid "Longer than"
584
  msgstr ""
585
 
586
+ #: ../dashboard.php:2883
587
  msgid "Refresh"
588
  msgstr ""
589
 
590
+ #: ../dashboard.php:3104
591
  msgid "Any"
592
  msgstr ""
593
 
594
+ #: ../dashboard.php:3144
595
  msgid "Advanced search"
596
  msgstr ""
597
 
615
  msgid "Gregory"
616
  msgstr ""
617
 
618
+ #: ../common.php:101
619
+ msgid "Check for requests"
620
  msgstr ""
621
 
622
+ #: ../common.php:134
623
+ msgid "Malicious activities mitigated"
 
624
  msgstr ""
625
 
626
+ #: ../common.php:137
627
+ msgid "Spam comments denied"
 
 
 
 
 
 
 
 
 
 
 
628
  msgstr ""
629
 
630
+ #: ../common.php:138
631
+ msgid "Spam form submissions denied"
 
 
632
  msgstr ""
633
 
634
+ #: ../common.php:139
635
+ msgid "Malicious IP addresses detected"
 
 
636
  msgstr ""
637
 
638
+ #: ../common.php:140
639
+ msgid "Lockouts occurred"
 
 
 
640
  msgstr ""
641
 
642
+ #: ../common.php:194 ../common.php:251 ../common.php:256 ../common.php:261 ..
643
+ #: /cerber-load.php:659 ../cerber-load.php:671 ../cerber-load.php:678 ../cerber-
644
+ #: load.php:906 ../cerber-load.php:1122 ../cerber-load.php:1128 ../cerber-load.
645
+ #: php:1133 ../cerber-load.php:1138 ../cerber-load.php:1144 ../cerber-load.php:
646
+ #: 1151 ../cerber-load.php:1251 ../cerber-load.php:1388 ../settings.php:780 ..
647
+ #: /settings.php:851
648
+ msgid "ERROR:"
649
  msgstr ""
650
 
651
+ #: ../common.php:740
652
+ msgid "User created"
653
  msgstr ""
654
 
655
+ #: ../common.php:742
656
+ msgid "Logged in"
657
  msgstr ""
658
 
659
+ #: ../common.php:743
660
+ msgid "Logged out"
661
  msgstr ""
662
 
663
+ #: ../common.php:744
664
+ msgid "Login failed"
665
  msgstr ""
666
 
667
+ #: ../common.php:747
668
+ msgid "IP blocked"
669
  msgstr ""
670
 
671
+ #: ../common.php:748
672
+ msgid "Subnet blocked"
 
673
  msgstr ""
674
 
675
+ #: ../common.php:750
676
+ msgid "Citadel activated!"
 
677
  msgstr ""
678
 
679
+ #: ../common.php:751
680
+ msgid "Spam comment denied"
681
  msgstr ""
682
 
683
+ #: ../common.php:752
684
+ msgid "Spam form submission denied"
685
  msgstr ""
686
 
687
+ #: ../common.php:753
688
+ msgid "Form submission denied"
689
  msgstr ""
690
 
691
+ #: ../common.php:754
692
+ msgid "Comment denied"
693
  msgstr ""
694
 
695
+ #: ../common.php:765
696
+ msgid "Password changed"
 
697
  msgstr ""
698
 
699
+ #: ../common.php:766
700
+ msgid "Password reset requested"
701
  msgstr ""
702
 
703
+ #: ../common.php:768
704
+ msgid "reCAPTCHA verification failed"
705
  msgstr ""
706
 
707
+ #: ../common.php:769
708
+ msgid "reCAPTCHA settings are incorrect"
709
  msgstr ""
710
 
711
+ #: ../common.php:770
712
+ msgid "Request to the Google reCAPTCHA service failed"
713
  msgstr ""
714
 
715
+ #: ../common.php:772
716
+ msgid "Attempt to access prohibited URL"
717
  msgstr ""
718
 
719
+ #: ../common.php:773 ../common.php:821
720
+ msgid "Attempt to log in with non-existent username"
721
  msgstr ""
722
 
723
+ #: ../common.php:774 ../common.php:822
724
+ msgid "Attempt to log in with prohibited username"
725
  msgstr ""
726
 
727
+ #: ../common.php:776
728
+ msgid "Attempt to log in denied"
729
  msgstr ""
730
 
731
+ #: ../common.php:777
732
+ msgid "Attempt to register denied"
733
  msgstr ""
734
 
735
+ #: ../common.php:778 ../common.php:826
736
+ msgid "Probing for vulnerable PHP code"
737
  msgstr ""
738
 
739
+ #: ../common.php:779
740
+ msgid "Attempt to upload executable file denied"
741
  msgstr ""
742
 
743
+ #: ../common.php:780
744
+ msgid "File upload denied"
745
  msgstr ""
746
 
747
+ #: ../common.php:782
748
+ msgid "Request to REST API denied"
749
  msgstr ""
750
 
751
+ #: ../common.php:783
752
+ msgid "XML-RPC request denied"
753
  msgstr ""
754
 
755
+ #: ../common.php:787
756
+ msgid "Bot detected"
757
  msgstr ""
758
 
759
+ #: ../common.php:788
760
+ msgid "Citadel mode is active"
761
  msgstr ""
762
 
763
+ #: ../common.php:790
764
+ msgid "IP blacklisted"
765
  msgstr ""
766
 
767
+ #: ../common.php:793
768
+ msgid "Malicious activity detected"
769
  msgstr ""
770
 
771
+ #: ../common.php:794
772
+ msgid "Blocked by country rule"
773
  msgstr ""
774
 
775
+ #: ../common.php:795
776
+ msgid "Limit reached"
 
777
  msgstr ""
778
 
779
+ #: ../common.php:796
780
+ msgid "Multiple suspicious activities"
781
  msgstr ""
782
 
783
+ #: ../common.php:819
784
+ msgid "Limit on login attempts is reached"
785
  msgstr ""
786
 
787
+ #: ../common.php:820
788
+ msgid "Attempt to access"
789
  msgstr ""
790
 
791
+ #: ../common.php:823
792
+ msgid "Limit on failed reCAPTCHA verifications is reached"
793
  msgstr ""
794
 
795
+ #: ../common.php:824
796
+ msgid "Bot activity is detected"
797
  msgstr ""
798
 
799
+ #: ../common.php:825
800
+ msgid "Multiple suspicious activities were detected"
801
  msgstr ""
802
 
803
+ #: ../common.php:881
804
  #, php-format
805
+ msgid "%s ago"
806
  msgstr ""
807
 
808
+ #: ../common.php:1015 ../settings.php:214
809
+ msgid "New version is available"
810
+ msgstr ""
811
+
812
+ #: ../common.php:1022
813
  #, php-format
814
+ msgid "Update to version %s of WP Cerber"
815
  msgstr ""
816
 
817
+ #: ../common.php:1041
818
+ msgid "Not specified"
819
  msgstr ""
820
 
821
+ #: ../common.php:1418
822
+ msgid "Unable to create the directory"
823
  msgstr ""
824
 
825
+ #: ../common.php:1423
826
+ msgid "Destination folder access denied"
827
  msgstr ""
828
 
829
+ #: ../common.php:1426
830
+ msgid "File not found"
 
831
  msgstr ""
832
 
833
+ #: ../common.php:1429
834
+ msgid "Unable to copy the file"
835
  msgstr ""
836
 
837
+ #: ../common.php:1435
838
+ msgid "Unable to delete the file"
839
  msgstr ""
840
 
841
+ #: ../cerber-news.php:159
842
+ msgid "Cool!"
843
  msgstr ""
844
 
845
+ #: ../cerber-lab.php:705
846
+ msgid "Want to make WP Cerber even more powerful?"
847
  msgstr ""
848
 
849
+ #: ../cerber-lab.php:706
850
+ msgid ""
851
+ "Allow WP Cerber to send locked out malicious IP addresses to Cerber Lab. "
852
+ "This helps the plugin team to develop new algorithms for WP Cerber that will "
853
+ "defend WordPress against new threats and botnets that are appearing "
854
+ "everyday. You can disable the sending in the plugin settings at any time."
855
  msgstr ""
856
 
857
+ #: ../cerber-lab.php:707
858
+ msgid "OK, nail them all"
859
  msgstr ""
860
 
861
+ #: ../cerber-lab.php:708
862
+ msgid "NO, maybe later"
863
  msgstr ""
864
 
865
+ #: ../cerber-lab.php:709 ../settings.php:362
866
+ msgid "Know more"
867
  msgstr ""
868
 
869
+ #: ../cerber-load.php:351
870
+ msgid "You are not allowed to log in. Ask your administrator for assistance."
871
  msgstr ""
872
 
873
+ #: ../cerber-load.php:357
874
+ #, php-format
875
+ msgid "You have reached the login attempts limit. Please try again in %d minutes."
876
  msgstr ""
877
 
878
+ #: ../cerber-load.php:376
879
+ #, php-format
880
+ msgid "You have only one attempt remaining."
881
+ msgid_plural "You have %d attempts remaining."
882
+ msgstr[0] ""
883
+ msgstr[1] ""
884
+
885
+ #: ../cerber-load.php:688
886
+ msgid ""
887
+ "Human verification failed. Please click the square box in the reCAPTCHA "
888
+ "block below."
889
  msgstr ""
890
 
891
+ #: ../cerber-load.php:785
892
+ msgid ""
893
+ "> > > Translator of WP Cerber? To get the PRO license for free, drop your "
894
+ "contacts here: https://wpcerber.com/contact/"
895
  msgstr ""
896
 
897
+ #: ../cerber-load.php:918
898
+ #, php-format
899
+ msgid ""
900
+ "<strong>ERROR</strong>: The password you entered for the username %s is "
901
+ "incorrect."
902
  msgstr ""
903
 
904
+ #: ../cerber-load.php:1123 ../cerber-load.php:1129 ../cerber-load.php:1145 ..
905
+ #: /cerber-load.php:1152
906
+ msgid "You are not allowed to register."
907
  msgstr ""
908
 
909
+ #: ../cerber-load.php:1139
910
+ msgid "Username is not allowed. Please choose another one."
911
  msgstr ""
912
 
913
+ #: ../cerber-load.php:1388
914
+ msgid "Sorry, human verification failed."
915
  msgstr ""
916
 
917
+ #: ../cerber-load.php:3085
918
+ msgid "We're sorry, you are not allowed to proceed"
919
  msgstr ""
920
 
921
+ #: ../cerber-load.php:3195
922
+ msgid "WP Cerber notify"
923
  msgstr ""
924
 
925
+ #: ../cerber-load.php:3217
926
+ msgid "Citadel mode is activated"
927
  msgstr ""
928
 
929
+ #: ../cerber-load.php:3219
930
+ #, php-format
931
+ msgid "Citadel mode is activated after %d failed login attempts in %d minutes."
932
  msgstr ""
933
 
934
+ #: ../cerber-load.php:3220
935
+ #, php-format
936
+ msgid "Last failed attempt was at %s from IP %s with user login: %s."
937
  msgstr ""
938
 
939
+ #: ../cerber-load.php:3221 ../cerber-load.php:3778
940
+ msgid "View activity in dashboard"
941
  msgstr ""
942
 
943
+ #: ../cerber-load.php:3246
944
+ msgid "unspecified"
945
  msgstr ""
946
 
947
+ #: ../cerber-load.php:3249
948
+ msgid "Number of lockouts is increasing"
949
  msgstr ""
950
 
951
+ #: ../cerber-load.php:3251
952
+ msgid "Number of active lockouts"
953
  msgstr ""
954
 
955
+ #: ../cerber-load.php:3252
956
+ #, php-format
957
+ msgid "Last lockout was added: %s for IP %s"
958
  msgstr ""
959
 
960
+ #: ../cerber-load.php:3254
961
+ msgid "View activity for this IP"
962
  msgstr ""
963
 
964
+ #: ../cerber-load.php:3255
965
+ msgid "View lockouts in dashboard"
966
  msgstr ""
967
 
968
+ #: ../cerber-load.php:3258 ../cerber-load.php:3260
969
+ msgid "A new version of WP Cerber is available to install"
970
  msgstr ""
971
 
972
+ #: ../cerber-load.php:3259
973
+ msgid "Hi!"
974
  msgstr ""
975
 
976
+ #: ../cerber-load.php:3262 ../cerber-load.php:3273
977
+ msgid "Website"
978
  msgstr ""
979
 
980
+ #: ../cerber-load.php:3265 ../cerber-load.php:3266
981
+ msgid "The WP Cerber security plugin has been deactivated"
982
  msgstr ""
983
 
984
+ #: ../cerber-load.php:3268
985
+ msgid "Not logged in"
986
  msgstr ""
987
 
988
+ #: ../cerber-load.php:3274
989
+ msgid "By user"
990
  msgstr ""
991
 
992
+ #: ../cerber-load.php:3275
993
+ msgid "From IP address"
994
  msgstr ""
995
 
996
+ #: ../cerber-load.php:3278
997
+ msgid "From country"
998
  msgstr ""
999
 
1000
+ #: ../cerber-load.php:3282
1001
+ msgid "The WP Cerber security plugin is now active"
1002
  msgstr ""
1003
 
1004
+ #: ../cerber-load.php:3283 ../cerber-load.php:3968
1005
+ msgid "WP Cerber is now active and has started protecting your site"
1006
  msgstr ""
1007
 
1008
+ #: ../cerber-load.php:3291
1009
+ msgid "New Custom login URL"
1010
  msgstr ""
1011
 
1012
+ #: ../cerber-load.php:3295 ../cerber-load.php:3296
1013
+ msgid "A new activity has been recorded"
1014
  msgstr ""
1015
 
1016
+ #: ../cerber-load.php:3301
1017
+ msgid "Weekly report"
1018
  msgstr ""
1019
 
1020
+ #: ../cerber-load.php:3304
1021
+ msgid "To change reporting settings visit"
1022
  msgstr ""
1023
 
1024
+ #: ../cerber-load.php:3330
1025
+ msgid "Your login page:"
1026
  msgstr ""
1027
 
1028
+ #: ../cerber-load.php:3334
1029
+ msgid "Your license is valid until"
1030
  msgstr ""
1031
 
1032
+ #: ../cerber-load.php:3337
1033
+ msgid "This message was sent by"
1034
  msgstr ""
1035
 
1036
+ #: ../cerber-load.php:3358
1037
  #, php-format
1038
+ msgid "Your last sign-in was %s from %s"
1039
  msgstr ""
1040
 
1041
+ #: ../cerber-load.php:3433
1042
+ msgid "Weekly Report"
1043
+ msgstr ""
1044
+
1045
+ #: ../cerber-load.php:3445
1046
+ msgid "Activity details"
1047
  msgstr ""
1048
 
1049
+ #: ../cerber-load.php:3459
1050
+ msgid "Attempts to log in with non-existent username"
1051
+ msgstr ""
1052
+
1053
+ #: ../cerber-load.php:3750
1054
+ msgid "User"
1055
+ msgstr ""
1056
+
1057
+ #: ../cerber-load.php:3758
1058
+ msgid "Search string"
1059
+ msgstr ""
1060
+
1061
+ #: ../cerber-load.php:3779
1062
+ msgid "To unsubscribe click here"
1063
+ msgstr ""
1064
+
1065
+ #: ../cerber-load.php:3936
1066
  #, php-format
1067
+ msgid "The WP Cerber requires PHP %s or higher. You are running"
1068
  msgstr ""
1069
 
1070
+ #: ../cerber-load.php:3940
1071
+ #, php-format
1072
+ msgid "The WP Cerber requires WordPress %s or higher. You are running"
1073
  msgstr ""
1074
 
1075
+ #: ../cerber-load.php:3949
1076
+ msgid "Can't activate WP Cerber due to a database error."
1077
  msgstr ""
1078
 
1079
+ #: ../cerber-load.php:3969
1080
+ msgid "Your IP address is added to the"
1081
  msgstr ""
1082
 
1083
+ #: ../cerber-load.php:3976 ../settings.php:394
1084
+ msgid "Main Settings"
 
 
 
 
1085
  msgstr ""
1086
 
1087
+ #: ../cerber-load.php:3977 ../settings.php:397 ../cerber-tools.php:88 ../cerber-
1088
+ #: tools.php:97 ../cerber-tools.php:178
1089
+ msgid "Access Lists"
1090
  msgstr ""
1091
 
1092
+ #: ../cerber-load.php:3979 ../settings.php:399
1093
+ msgid "Hardening"
1094
  msgstr ""
1095
 
1096
+ #: ../cerber-load.php:3980 ../settings.php:78 ../settings.php:95 ../settings.php:
1097
+ #: 404
1098
+ msgid "Notifications"
1099
+ msgstr ""
1100
+
1101
+ #: ../cerber-load.php:3981
1102
+ msgid "Import settings"
1103
  msgstr ""
1104
 
1105
  #: ../settings.php:70
1106
+ msgid "Plugin initialization"
1107
  msgstr ""
1108
 
1109
  #: ../settings.php:71
1110
+ msgid "Load security engine"
1111
+ msgstr ""
1112
+
1113
+ #: ../settings.php:71
1114
+ msgid "Legacy mode"
1115
+ msgstr ""
1116
+
1117
+ #: ../settings.php:71
1118
+ msgid "Standard mode"
1119
+ msgstr ""
1120
+
1121
+ #: ../settings.php:73
1122
+ msgid "Limit login attempts"
1123
+ msgstr ""
1124
+
1125
+ #: ../settings.php:74
1126
  msgid "Attempts"
1127
  msgstr ""
1128
 
1129
+ #: ../settings.php:75
1130
  msgid "Lockout duration"
1131
  msgstr ""
1132
 
1133
+ #: ../settings.php:75 ../settings.php:94
1134
  msgid "minutes"
1135
  msgstr ""
1136
 
1137
+ #: ../settings.php:76
1138
  msgid "Aggressive lockout"
1139
  msgstr ""
1140
 
1141
+ #: ../settings.php:77
1142
  msgid "Apply limit login rules to IP addresses in the White IP Access List"
1143
  msgstr ""
1144
 
1145
+ #: ../settings.php:79
1146
  msgid "Site connection"
1147
  msgstr ""
1148
 
1149
+ #: ../settings.php:81
1150
  msgid "Proactive security rules"
1151
  msgstr ""
1152
 
1153
+ #: ../settings.php:82
1154
  msgid "Block subnet"
1155
  msgstr ""
1156
 
1157
+ #: ../settings.php:82
1158
  msgid "Always block entire subnet Class C of intruders IP"
1159
  msgstr ""
1160
 
1161
+ #: ../settings.php:83
1162
  msgid "Non-existent users"
1163
  msgstr ""
1164
 
1165
+ #: ../settings.php:83
1166
  msgid "Immediately block IP when attempting to login with a non-existent username"
1167
  msgstr ""
1168
 
1169
+ #: ../settings.php:84
1170
  msgid "Redirect dashboard requests"
1171
  msgstr ""
1172
 
1173
+ #: ../settings.php:84
1174
  msgid ""
1175
  "Disable automatic redirecting to the login page when /wp-admin/ is requested "
1176
  "by an unauthorized request"
1177
  msgstr ""
1178
 
1179
+ #: ../settings.php:85
1180
  msgid "Request wp-login.php"
1181
  msgstr ""
1182
 
1183
+ #: ../settings.php:85
1184
  msgid "Immediately block IP after any request to wp-login.php"
1185
  msgstr ""
1186
 
1187
+ #: ../settings.php:86
1188
  msgid "Display 404 page"
1189
  msgstr ""
1190
 
1191
+ #: ../settings.php:86
1192
  msgid "Use 404 template from the active theme"
1193
  msgstr ""
1194
 
1195
+ #: ../settings.php:86
1196
  msgid "Display simple 404 page"
1197
  msgstr ""
1198
 
1199
+ #: ../settings.php:88
1200
  msgid "Custom login page"
1201
  msgstr ""
1202
 
1203
+ #: ../settings.php:89
1204
  msgid "Custom login URL"
1205
  msgstr ""
1206
 
1207
+ #: ../settings.php:89
1208
  msgid "must not overlap with the existing pages or posts slug"
1209
  msgstr ""
1210
 
1211
+ #: ../settings.php:90
1212
  msgid "Disable wp-login.php"
1213
  msgstr ""
1214
 
1215
+ #: ../settings.php:90
1216
  msgid "Block direct access to wp-login.php and return HTTP 404 Not Found Error"
1217
  msgstr ""
1218
 
1219
+ #: ../settings.php:93
1220
  msgid "Threshold"
1221
  msgstr ""
1222
 
1223
+ #: ../settings.php:94
1224
  msgid "Duration"
1225
  msgstr ""
1226
 
1227
+ #: ../settings.php:95
1228
  msgid "Send notification to admin email"
1229
  msgstr ""
1230
 
1231
+ #: ../settings.php:95 ../settings.php:532 ../settings.php:654
1232
  msgid "Click to send test"
1233
  msgstr ""
1234
 
1235
+ #: ../settings.php:98 ../settings.php:330
1236
  msgid "Keep records for"
1237
  msgstr ""
1238
 
1239
+ #: ../settings.php:98 ../settings.php:172 ../settings.php:334
1240
  msgid "days"
1241
  msgstr ""
1242
 
1243
+ #: ../settings.php:99
1244
  msgid "Cerber Lab connection"
1245
  msgstr ""
1246
 
1247
+ #: ../settings.php:99
1248
  msgid "Send malicious IP addresses to the Cerber Lab"
1249
  msgstr ""
1250
 
1251
+ #: ../settings.php:100
1252
  msgid "Cerber Lab protocol"
1253
  msgstr ""
1254
 
1255
+ #: ../settings.php:101
1256
  msgid "Use file"
1257
  msgstr ""
1258
 
1259
+ #: ../settings.php:101
1260
  msgid "Write failed login attempts to the file"
1261
  msgstr ""
1262
 
1263
+ #: ../settings.php:103
1264
  msgid "Preferences"
1265
  msgstr ""
1266
 
1267
+ #: ../settings.php:104
1268
  msgid "Drill down IP"
1269
  msgstr ""
1270
 
1271
+ #: ../settings.php:104
1272
  msgid "Retrieve extra WHOIS information for IP"
1273
  msgstr ""
1274
 
1275
+ #: ../settings.php:105
1276
  msgid "Date format"
1277
  msgstr ""
1278
 
1279
+ #: ../settings.php:105
1280
  #, php-format
1281
  msgid "if empty, the default format %s will be used"
1282
  msgstr ""
1283
 
1284
+ #: ../settings.php:112
1285
  msgid "Hardening WordPress"
1286
  msgstr ""
1287
 
1288
+ #: ../settings.php:113
1289
  msgid "Stop user enumeration"
1290
  msgstr ""
1291
 
1292
+ #: ../settings.php:113
1293
  msgid "Block access to user pages like /?author=n and user data via REST API"
1294
  msgstr ""
1295
 
1296
+ #: ../settings.php:114
1297
  msgid "Protect admin scripts"
1298
  msgstr ""
1299
 
1300
+ #: ../settings.php:114
1301
  msgid "Block unauthorized access to load-scripts.php and load-styles.php"
1302
  msgstr ""
1303
 
1304
+ #: ../settings.php:115
1305
  msgid "Disable XML-RPC"
1306
  msgstr ""
1307
 
1308
+ #: ../settings.php:115
1309
  msgid "Block access to the XML-RPC server (including Pingbacks and Trackbacks)"
1310
  msgstr ""
1311
 
1312
+ #: ../settings.php:116
1313
  msgid "Disable feeds"
1314
  msgstr ""
1315
 
1316
+ #: ../settings.php:116
1317
  msgid "Block access to the RSS, Atom and RDF feeds"
1318
  msgstr ""
1319
 
1320
+ #: ../settings.php:117
1321
  msgid "Disable REST API"
1322
  msgstr ""
1323
 
1324
+ #: ../settings.php:117
1325
  msgid "Block access to the WordPress REST API except the following"
1326
  msgstr ""
1327
 
1328
+ #: ../settings.php:118
1329
  msgid "Allow REST API for logged in users"
1330
  msgstr ""
1331
 
1332
+ #: ../settings.php:125
1333
  msgid ""
1334
  "Specify REST API namespaces to be allowed if REST API is disabled. One "
1335
  "string per line."
1336
  msgstr ""
1337
 
1338
+ #: ../settings.php:135
1339
  msgid "User related settings"
1340
  msgstr ""
1341
 
1342
+ #: ../settings.php:136
1343
  msgid "Registration limit"
1344
  msgstr ""
1345
 
1346
+ #: ../settings.php:137
1347
  msgid "Prohibited usernames"
1348
  msgstr ""
1349
 
1350
+ #: ../settings.php:143
1351
  msgid ""
1352
  "Usernames from this list are not allowed to log in or register. Any IP "
1353
  "address, have tried to use any of these usernames, will be immediately "
1354
  "blocked. Use comma to separate logins."
1355
  msgstr ""
1356
 
1357
+ #: ../settings.php:143
1358
  msgid "To specify a REGEX pattern wrap a pattern in two forward slashes."
1359
  msgstr ""
1360
 
1361
+ #: ../settings.php:145
1362
  msgid "User session expire"
1363
  msgstr ""
1364
 
1365
+ #: ../settings.php:145
1366
  msgid "in minutes (leave empty to use default WP value)"
1367
  msgstr ""
1368
 
1369
+ #: ../settings.php:146
1370
  msgid "Sort users in dashboard"
1371
  msgstr ""
1372
 
1373
+ #: ../settings.php:146
1374
  msgid "by date of registration"
1375
  msgstr ""
1376
 
1377
+ #: ../settings.php:153
1378
  msgid "Cerber antispam engine"
1379
  msgstr ""
1380
 
1381
+ #: ../settings.php:154
1382
  msgid "Comment form"
1383
  msgstr ""
1384
 
1385
+ #: ../settings.php:154
1386
  msgid "Protect comment form with bot detection engine"
1387
  msgstr ""
1388
 
1389
+ #: ../settings.php:155 ../settings.php:180
1390
  msgid "Registration form"
1391
  msgstr ""
1392
 
1393
+ #: ../settings.php:155
1394
  msgid "Protect registration form with bot detection engine"
1395
  msgstr ""
1396
 
1397
+ #: ../settings.php:156
1398
  msgid "Other forms"
1399
  msgstr ""
1400
 
1401
+ #: ../settings.php:156
1402
  msgid "Protect all forms on the website with bot detection engine"
1403
  msgstr ""
1404
 
1405
+ #: ../settings.php:158
1406
  msgid "Adjust antispam engine"
1407
  msgstr ""
1408
 
1409
+ #: ../settings.php:159
1410
  msgid "Safe mode"
1411
  msgstr ""
1412
 
1413
+ #: ../settings.php:159
1414
  msgid "Use less restrictive policies (allow AJAX)"
1415
  msgstr ""
1416
 
1417
+ #: ../settings.php:160
1418
  msgid "Disable bot detection engine for logged in users"
1419
  msgstr ""
1420
 
1421
+ #: ../settings.php:161
1422
  msgid "Query whitelist"
1423
  msgstr ""
1424
 
1425
+ #: ../settings.php:167
1426
  msgid ""
1427
  "Enter a part of query string or query path to exclude a request from "
1428
  "inspection by the engine. One item per line."
1429
  msgstr ""
1430
 
1431
+ #: ../settings.php:170
1432
  msgid "Comment processing"
1433
  msgstr ""
1434
 
1435
+ #: ../settings.php:171
1436
  msgid "If a spam comment detected"
1437
  msgstr ""
1438
 
1439
+ #: ../settings.php:171
1440
  msgid "Deny it completely"
1441
  msgstr ""
1442
 
1443
+ #: ../settings.php:171
1444
  msgid "Mark it as spam"
1445
  msgstr ""
1446
 
1447
+ #: ../settings.php:172
1448
  msgid "Trash spam comments"
1449
  msgstr ""
1450
 
1451
+ #: ../settings.php:172
1452
  msgid "Move spam comments to trash after"
1453
  msgstr ""
1454
 
1455
+ #: ../settings.php:175
1456
  msgid "reCAPTCHA settings"
1457
  msgstr ""
1458
 
1459
+ #: ../settings.php:176
1460
  msgid "Site key"
1461
  msgstr ""
1462
 
1463
+ #: ../settings.php:177
1464
  msgid "Secret key"
1465
  msgstr ""
1466
 
1467
+ #: ../settings.php:178
1468
  msgid "Invisible reCAPTCHA"
1469
  msgstr ""
1470
 
1471
+ #: ../settings.php:178
1472
  msgid "Enable invisible reCAPTCHA"
1473
  msgstr ""
1474
 
1475
+ #: ../settings.php:178
1476
  msgid ""
1477
  "(do not enable it unless you get and enter the Site and Secret keys for the "
1478
  "invisible version)"
1479
  msgstr ""
1480
 
1481
+ #: ../settings.php:180
1482
  msgid "Enable reCAPTCHA for WordPress registration form"
1483
  msgstr ""
1484
 
1485
+ #: ../settings.php:181
1486
  msgid "Enable reCAPTCHA for WooCommerce registration form"
1487
  msgstr ""
1488
 
1489
+ #: ../settings.php:183
1490
  msgid "Lost password form"
1491
  msgstr ""
1492
 
1493
+ #: ../settings.php:183
1494
  msgid "Enable reCAPTCHA for WordPress lost password form"
1495
  msgstr ""
1496
 
1497
+ #: ../settings.php:184
1498
  msgid "Enable reCAPTCHA for WooCommerce lost password form"
1499
  msgstr ""
1500
 
1501
+ #: ../settings.php:186
1502
  msgid "Login form"
1503
  msgstr ""
1504
 
1505
+ #: ../settings.php:186
1506
  msgid "Enable reCAPTCHA for WordPress login form"
1507
  msgstr ""
1508
 
1509
+ #: ../settings.php:187
1510
  msgid "Enable reCAPTCHA for WooCommerce login form"
1511
  msgstr ""
1512
 
1513
+ #: ../settings.php:189
1514
  msgid "Enable reCAPTCHA for WordPress comment form"
1515
  msgstr ""
1516
 
1517
+ #: ../settings.php:190
1518
  msgid "Disable reCAPTCHA for logged in users"
1519
  msgstr ""
1520
 
1521
+ #: ../settings.php:192
1522
  msgid "Limit attempts"
1523
  msgstr ""
1524
 
1525
+ #: ../settings.php:192
1526
  #, php-format
1527
  msgid "Lock out IP address for %s minutes after %s failed attempts within %s minutes"
1528
  msgstr ""
1529
 
1530
+ #: ../settings.php:198
1531
  msgid "Email notifications"
1532
  msgstr ""
1533
 
1534
+ #: ../settings.php:201 ../settings.php:236
1535
  msgid "Email Address"
1536
  msgstr ""
1537
 
1538
+ #: ../settings.php:205 ../settings.php:241 ../settings.php:298
1539
  msgid "Use comma to specify multiple values"
1540
  msgstr ""
1541
 
1542
+ #: ../settings.php:210
1543
  #, php-format
1544
  msgid "if empty, the admin email %s will be used"
1545
  msgstr ""
1546
 
1547
+ #: ../settings.php:213
1548
  msgid "Notification limit"
1549
  msgstr ""
1550
 
1551
+ #: ../settings.php:213
1552
  msgid "notification letters allowed per hour (0 means unlimited)"
1553
  msgstr ""
1554
 
1555
+ #: ../settings.php:219
1556
  msgid "Push notifications"
1557
  msgstr ""
1558
 
1559
+ #: ../settings.php:226
1560
  msgid "All connected devices"
1561
  msgstr ""
1562
 
1563
+ #: ../settings.php:227
1564
  msgid "No devices found"
1565
  msgstr ""
1566
 
1567
+ #: ../settings.php:229
1568
  msgid "Not available"
1569
  msgstr ""
1570
 
1571
+ #: ../settings.php:233
1572
  msgid "Weekly reports"
1573
  msgstr ""
1574
 
1575
+ #: ../settings.php:234
1576
  msgid "Enable reporting"
1577
  msgstr ""
1578
 
1579
+ #: ../settings.php:246
1580
  msgid "if empty, email from notification settings will be used"
1581
  msgstr ""
1582
 
1583
+ #: ../settings.php:254
1584
  msgid "Inspection"
1585
  msgstr ""
1586
 
1587
+ #: ../settings.php:255
1588
  msgid "Enable traffic inspection"
1589
  msgstr ""
1590
 
1591
+ #: ../settings.php:260
1592
  msgid "Request whitelist"
1593
  msgstr ""
1594
 
1595
+ #: ../settings.php:266
1596
  msgid ""
1597
  "Enter a request URI to exclude the request from inspection. One item per "
1598
  "line."
1599
  msgstr ""
1600
 
1601
+ #: ../settings.php:269
1602
  msgid "Logging"
1603
  msgstr ""
1604
 
1605
+ #: ../settings.php:270
1606
  msgid "Logging mode"
1607
  msgstr ""
1608
 
1609
+ #: ../settings.php:276
1610
  msgid "Logging disabled"
1611
  msgstr ""
1612
 
1613
+ #: ../settings.php:277
1614
  msgid "Smart"
1615
  msgstr ""
1616
 
1617
+ #: ../settings.php:278
1618
  msgid "All traffic"
1619
  msgstr ""
1620
 
1621
+ #: ../settings.php:282
1622
  msgid "Ignore crawlers"
1623
  msgstr ""
1624
 
1625
+ #: ../settings.php:287
1626
  msgid "Save request fields"
1627
  msgstr ""
1628
 
1629
+ #: ../settings.php:292
1630
  msgid "Mask these form fields"
1631
  msgstr ""
1632
 
1633
+ #: ../settings.php:303
1634
  msgid "Save request headers"
1635
  msgstr ""
1636
 
1637
+ #: ../settings.php:309
1638
  msgid "Save $_SERVER"
1639
  msgstr ""
1640
 
1641
+ #: ../settings.php:315
1642
  msgid "Save request cookies"
1643
  msgstr ""
1644
 
1645
+ #: ../settings.php:322
1646
  msgid "Page generation time threshold"
1647
  msgstr ""
1648
 
1649
+ #: ../settings.php:327
1650
  msgid "milliseconds"
1651
  msgstr ""
1652
 
1653
+ #: ../settings.php:344
1654
  msgid "Make your protection smarter!"
1655
  msgstr ""
1656
 
1657
+ #: ../settings.php:348
1658
  msgid ""
1659
  "Please enable Permalinks to use this feature. Set Permalink Settings to "
1660
  "something other than Default."
1661
  msgstr ""
1662
 
1663
+ #: ../settings.php:351
1664
  msgid ""
1665
  "Be careful when enabling this options. If you forget the custom login URL "
1666
  "you will not be able to login."
1667
  msgstr ""
1668
 
1669
+ #: ../settings.php:355
1670
  msgid ""
1671
  "In the Citadel mode nobody is able to log in except IPs from the White IP "
1672
  "Access List. Active user sessions will not be affected."
1673
  msgstr ""
1674
 
1675
+ #: ../settings.php:358
1676
  msgid "These settings do not affect hosts from the "
1677
  msgstr ""
1678
 
1679
+ #: ../settings.php:361
1680
  msgid ""
1681
  "Before you can start using reCAPTCHA, you have to obtain Site key and Secret "
1682
  "key on the Google website"
1683
  msgstr ""
1684
 
1685
+ #: ../settings.php:392
1686
  msgid "Lockouts"
1687
  msgstr ""
1688
 
1689
+ #: ../settings.php:401
1690
  msgid "Users"
1691
  msgstr ""
1692
 
1693
+ #: ../settings.php:406
1694
  msgid "Help"
1695
  msgstr ""
1696
 
1697
+ #: ../settings.php:513 ../settings.php:635
1698
  #, php-format
1699
  msgid "%s allowed retries in %s minutes"
1700
  msgstr ""
1701
 
1702
+ #: ../settings.php:518 ../settings.php:640
1703
  #, php-format
1704
  msgid "%s allowed registrations in %s minutes from one IP"
1705
  msgstr ""
1706
 
1707
+ #: ../settings.php:523 ../settings.php:645
1708
  #, php-format
1709
  msgid "Increase lockout duration to %s hours after %s lockouts in the last %s hours"
1710
  msgstr ""
1711
 
1712
+ #: ../settings.php:530 ../settings.php:652
1713
  msgid "Notify admin if the number of active lockouts above"
1714
  msgstr ""
1715
 
1716
+ #: ../settings.php:535 ../settings.php:657
1717
  #, php-format
1718
  msgid "Enable after %s failed login attempts in last %s minutes"
1719
  msgstr ""
1720
 
1721
+ #: ../settings.php:737
1722
  msgid "Sunday"
1723
  msgstr ""
1724
 
1725
+ #: ../settings.php:738
1726
  msgid "Monday"
1727
  msgstr ""
1728
 
1729
+ #: ../settings.php:739
1730
  msgid "Tuesday"
1731
  msgstr ""
1732
 
1733
+ #: ../settings.php:740
1734
  msgid "Wednesday"
1735
  msgstr ""
1736
 
1737
+ #: ../settings.php:741
1738
  msgid "Thursday"
1739
  msgstr ""
1740
 
1741
+ #: ../settings.php:742
1742
  msgid "Friday"
1743
  msgstr ""
1744
 
1745
+ #: ../settings.php:743
1746
  msgid "Saturday"
1747
  msgstr ""
1748
 
1749
  #. translators: preposition of time
1750
+ #: ../settings.php:753
1751
  msgctxt "preposition of time"
1752
  msgid "at"
1753
  msgstr ""
1754
 
1755
+ #: ../settings.php:769
1756
  msgid "Click to send now"
1757
  msgstr ""
1758
 
1759
+ #: ../settings.php:781
1760
+ msgid "Plugin initialization mode has not been changed"
1761
+ msgstr ""
1762
+
1763
+ #: ../settings.php:801 ../settings.php:802
1764
  msgid "Attention! You have changed the login URL! The new login URL is"
1765
  msgstr ""
1766
 
1767
+ #: ../settings.php:803 ../settings.php:804
1768
  msgid ""
1769
  "If you use a caching plugin, you have to add your new login URL to the list "
1770
  "of pages not to cache."
1771
  msgstr ""
1772
 
1773
+ #: ../settings.php:882 ../settings.php:894
1774
  msgid "<strong>ERROR</strong>: please enter a valid email address."
1775
  msgstr ""
1776
 
1847
  msgid "Error while parsing file"
1848
  msgstr ""
1849
 
1850
+ #: ../cerber-tools.php:339
1851
  msgid "Antispam and bot detection settings"
1852
  msgstr ""
1853
+
1854
+ #. Name of the plugin
1855
+ msgid "WP Cerber boot module"
1856
+ msgstr ""
1857
+
1858
+ #. Description of the plugin
1859
+ msgid ""
1860
+ "This is a standard boot module for WP Cerber Security & Antispam plugin. It "
1861
+ "was installed when you set the plugin initialization mode to Standard. Know "
1862
+ "more: <a href=\"https://wpcerber.com\">wpcerber.com</a>."
1863
+ msgstr ""
modules/aaa-wp-cerber.php ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: WP Cerber boot module
4
+ Plugin URI: https://wpcerber.com
5
+ Description: This is a standard boot module for WP Cerber Security & Antispam plugin. It was installed when you set the plugin initialization mode to Standard. Know more: <a href="https://wpcerber.com">wpcerber.com</a>.
6
+ Author: Gregory
7
+ Author URI: https://wpcerber.com
8
+ Version: 1.0
9
+ Text Domain: wp-cerber
10
+ Network: true
11
+
12
+ Copyright (C) 2015-18 CERBER TECH INC., http://cerber.tech
13
+ Copyright (C) 2015-18 Gregory Markov, https://wpcerber.com
14
+
15
+ Licenced under the GNU GPL.
16
+
17
+ This program is free software; you can redistribute it and/or modify
18
+ it under the terms of the GNU General Public License as published by
19
+ the Free Software Foundation; either version 3 of the License, or
20
+ (at your option) any later version.
21
+
22
+ This program is distributed in the hope that it will be useful,
23
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
24
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25
+ GNU General Public License for more details.
26
+
27
+ You should have received a copy of the GNU General Public License
28
+ along with this program; if not, write to the Free Software
29
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30
+
31
+ */
32
+
33
+ // If this file is called directly, abort executing.
34
+ if ( ! defined( 'WPINC' ) ) {
35
+ exit;
36
+ }
37
+
38
+ function cerber_mode(){
39
+ return 1;
40
+ }
41
+
42
+ if ( ( include_once WP_PLUGIN_DIR . '/wp-cerber/wp-cerber.php' ) == true ) {
43
+ define( 'CERBER_MODE', 1 );
44
+ }
readme.txt CHANGED
@@ -1,11 +1,11 @@
1
  === Cerber Security & Antispam ===
2
  Contributors: gioni
3
  Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=SR8RJXFU35EW8
4
- Tags: security, login, protect, antispam, limit login attempts, woocommerce, custom login, recaptcha, captcha, activity, log, logging, block, fail2ban, monitoring, rename wp login, whitelist, blacklist, wordpress security, xmlrpc, user enumeration, hardening, authentication, notification, pushbullet, wordfence, brute force, bruteforce, users
5
  Requires at least: 4.4
6
  Requires PHP: 5.3
7
  Tested up to: 4.9
8
- Stable tag: 6.2
9
  License: GPLv2
10
 
11
  Protection against hacker attacks and bots. Restrict access with IP access lists, track user and bot activity. reCAPTCHA. Limit login attempts.
@@ -13,10 +13,10 @@ Protection against hacker attacks and bots. Restrict access with IP access lists
13
  == Description ==
14
 
15
  Defends WordPress against brute force attacks by limiting the number of login attempts through the login form, XML-RPC / REST API requests or using auth cookies.
16
- Restricts access with a Black IP Access List and a White IP Access List.
17
  Tracks user and intruder activity with powerful email, mobile and desktop notifications.
18
  Stop spam: activates Cerber antispam engine and Google reCAPTCHA for protecting registration, contact and comments forms.
19
- Hardening WordPress with a set of security settings.
20
 
21
  **Features you will love**
22
 
@@ -25,19 +25,19 @@ Hardening WordPress with a set of security settings.
25
  * Permit or restrict access by [White IP Access list and Black IP Access List](https://wpcerber.com/using-ip-access-lists-to-protect-wordpress/) with a single IP, IP range or subnet.
26
  * Create **Custom login URL** ([rename wp-login.php](https://wpcerber.com/how-to-rename-wp-login-php/)).
27
  * Cerber antispam engine for protecting any contact form. Automatically detects and moves spam comments to trash or deny it completely.
28
- * Log user, bot and hacker activities.
29
- * Cool notifications with powerful filters for activities.
30
- * Hide wp-login.php, wp-signup.php and wp-register.php from possible attacks and return 404 HTTP Error.
31
- * Hide wp-admin (dashboard) and return 404 HTTP Error when a user isn't logged in.
32
- * Immediately block IP or subnet when attempting to log in with non-existent or prohibited username.
33
  * Restrict user registration or login with a username matching REGEX patterns.
34
- * Disable WP REST API or restrict access with your own rules
35
  * Disable XML-RPC (block access to the XML-RPC interface including Pingbacks and Trackbacks)
36
  * Disable feeds (block access to the RSS, Atom and RDF feeds)
37
- * Restrict access to XML-RPC, REST API and feeds by **White IP Access list** with IP or IP range.
38
- * Disable automatic redirecting to the login page.
39
  * **Stop user enumeration** (block access to pages like /?author=n and user REST API)
40
- * Proactively **block IP subnet class C** for intruder's IP.
41
  * Anti-spam: **reCAPTCHA** to protect WordPress login, register and comment forms.
42
  * [reCAPTCHA for WooCommerce & WordPress forms](https://wpcerber.com/how-to-setup-recaptcha/).
43
  * Invisible reCAPTCHA for WordPress comments forms
@@ -138,13 +138,14 @@ Installing the WP Cerber Security & Antispam plugin is the same as other WordPre
138
  2. Activate the WP Cerber through the Plugins > Installed Plugins menu in the WordPress admin dashboard.
139
  3. The plugin is now active and has started protecting your WordPress with default settings.
140
  4. Make sure, that you've got a notification letter to your site admin email.
 
141
  5. Read carefully: [Getting Started Guide](https://wpcerber.com/getting-started/)
142
 
143
  **Important notes**
144
 
145
- 1. Before enabling invisible reCAPTCHA, you must get separate keys for the invisible version. [How to enable reCAPTCHA](https://wpcerber.com/how-to-setup-recaptcha/).
146
  2. If you want to test out plugin's features, do this on another computer (or incognito browser window) and remove computer IP address or network from the White Access List. Cerber is smart enough to recognize "the boss".
147
- 3. If you've set up the Custom login URL and you use some caching plugin like **W3 Total Cache** or **WP Super Cache**, you have to add a new Custom login URL to the list of pages not to cache.
148
  4. [Read this if your website is under CloudFlare](https://wpcerber.com/cloudflare-and-wordpress-cerber/)
149
  5. If you use the Jetpack plugin or another plugin that needs to connect to wordpress.com, you need to unlock XML-RPC. To do that go to the Hardening tab, uncheck Disable XML-RPC, and click the Save changes button.
150
 
@@ -286,6 +287,17 @@ To get access to your dashboard you need to copy the WP Cerber Reset folder to t
286
 
287
  == Changelog ==
288
 
 
 
 
 
 
 
 
 
 
 
 
289
  = 6.2 =
290
  * New: Protection against (DoS) attacks that exploit recently discovered vulnerability (CVE-2018-6389).
291
  * New: The Traffic Inspector algorithm detects malformed and double extensions like .php.jpg more precisely.
1
  === Cerber Security & Antispam ===
2
  Contributors: gioni
3
  Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=SR8RJXFU35EW8
4
+ Tags: security, login, custom login url, antispam, limit login attempts, firewall, recaptcha, captcha, activity, log, logging, whitelist, blacklist, access list
5
  Requires at least: 4.4
6
  Requires PHP: 5.3
7
  Tested up to: 4.9
8
+ Stable tag: 6.5
9
  License: GPLv2
10
 
11
  Protection against hacker attacks and bots. Restrict access with IP access lists, track user and bot activity. reCAPTCHA. Limit login attempts.
13
  == Description ==
14
 
15
  Defends WordPress against brute force attacks by limiting the number of login attempts through the login form, XML-RPC / REST API requests or using auth cookies.
16
+ Restricts access with the Black IP Access List and the White IP Access List.
17
  Tracks user and intruder activity with powerful email, mobile and desktop notifications.
18
  Stop spam: activates Cerber antispam engine and Google reCAPTCHA for protecting registration, contact and comments forms.
19
+ Hardening WordPress with a set of security rules and comprehensive algorithms.
20
 
21
  **Features you will love**
22
 
25
  * Permit or restrict access by [White IP Access list and Black IP Access List](https://wpcerber.com/using-ip-access-lists-to-protect-wordpress/) with a single IP, IP range or subnet.
26
  * Create **Custom login URL** ([rename wp-login.php](https://wpcerber.com/how-to-rename-wp-login-php/)).
27
  * Cerber antispam engine for protecting any contact form. Automatically detects and moves spam comments to trash or deny it completely.
28
+ * Log users, bots, hacker and other suspicious activities.
29
+ * Cool notifications with powerful event filters.
30
+ * Hide wp-login.php, wp-signup.php and wp-register.php from possible attacks.
31
+ * Hide wp-admin (dashboard) when a user isn't logged in.
32
+ * Immediately block an IP or a subnet when attempting to log in with non-existent or prohibited username.
33
  * Restrict user registration or login with a username matching REGEX patterns.
34
+ * Disable WP REST API or restrict access with your own security rules
35
  * Disable XML-RPC (block access to the XML-RPC interface including Pingbacks and Trackbacks)
36
  * Disable feeds (block access to the RSS, Atom and RDF feeds)
37
+ * Restrict access to XML-RPC, REST API and feeds by **White IP Access list** by an IP address or an IP range.
38
+ * Disable automatic redirection to the login page.
39
  * **Stop user enumeration** (block access to pages like /?author=n and user REST API)
40
+ * Proactively **blocks IP subnet class C** for intruder's IP.
41
  * Anti-spam: **reCAPTCHA** to protect WordPress login, register and comment forms.
42
  * [reCAPTCHA for WooCommerce & WordPress forms](https://wpcerber.com/how-to-setup-recaptcha/).
43
  * Invisible reCAPTCHA for WordPress comments forms
138
  2. Activate the WP Cerber through the Plugins > Installed Plugins menu in the WordPress admin dashboard.
139
  3. The plugin is now active and has started protecting your WordPress with default settings.
140
  4. Make sure, that you've got a notification letter to your site admin email.
141
+ 5. It's advised to enable Standard mode for the "Load security engine" setting.
142
  5. Read carefully: [Getting Started Guide](https://wpcerber.com/getting-started/)
143
 
144
  **Important notes**
145
 
146
+ 1. Before enabling invisible reCAPTCHA, you must obtain separate keys for the invisible version. [How to enable reCAPTCHA](https://wpcerber.com/how-to-setup-recaptcha/).
147
  2. If you want to test out plugin's features, do this on another computer (or incognito browser window) and remove computer IP address or network from the White Access List. Cerber is smart enough to recognize "the boss".
148
+ 3. If you've set up the Custom login URL and you use some caching plugin like **W3 Total Cache** or **WP Super Cache**, you have to add the new Custom login URL to the list of pages not to cache.
149
  4. [Read this if your website is under CloudFlare](https://wpcerber.com/cloudflare-and-wordpress-cerber/)
150
  5. If you use the Jetpack plugin or another plugin that needs to connect to wordpress.com, you need to unlock XML-RPC. To do that go to the Hardening tab, uncheck Disable XML-RPC, and click the Save changes button.
151
 
287
 
288
  == Changelog ==
289
 
290
+ = 6.5 =
291
+ * New: A new, advanced initialization mode which reinforces overall security performance.
292
+ * New: Traffic Inspector's algorithms detect and deny any attempt to upload executable files or an .htaccess file via any POST request.
293
+ * New: A new setting to disable email notifications about new versions of the plugin.
294
+ * New: Search in the traffic log improved. Search in the User agent string and filter out the HTTP method (GET/POST) are available.
295
+ * Update: Performance of the logging subsystem is improved.
296
+ * Update: In the Smart mode if a user is not logged in, all requests to the admin dashboard are logged.
297
+ * Bug fixed: If a user tries to log in with an email address and an incorrect password, the "Invalid username" message is shown.
298
+ * Bug fixed: On a multisite installation with websites in subdirectories a user activation link doesn't work.
299
+ * [Read more](https://wpcerber.com/wp-cerber-security-6-5/)
300
+
301
  = 6.2 =
302
  * New: Protection against (DoS) attacks that exploit recently discovered vulnerability (CVE-2018-6389).
303
  * New: The Traffic Inspector algorithm detects malformed and double extensions like .php.jpg more precisely.
settings.php CHANGED
@@ -67,6 +67,9 @@ function cerber_settings_init(){
67
  $tab='main'; // 'cerber-main' settings
68
  register_setting( 'cerberus-'.$tab, 'cerber-'.$tab );
69
 
 
 
 
70
  add_settings_section('cerber', __('Limit login attempts','wp-cerber'), 'cerber_sapi_section', 'cerber-' . $tab);
71
  add_settings_field('attempts',__('Attempts','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'cerber',array('group'=>$tab,'option'=>'attempts','type'=>'attempts'));
72
  add_settings_field('lockout',__('Lockout duration','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'cerber',array('group'=>$tab,'option'=>'lockout','type'=>'text','label'=>__('minutes','wp-cerber'),'size'=>3));
@@ -208,6 +211,10 @@ function cerber_settings_init(){
208
  ) );
209
 
210
  add_settings_field('emailrate',__('Notification limit','wp-cerber'),'cerber_field_show',CERBER_OPT_N,'notify',array('group'=>$group,'setting'=>'emailrate','type'=>'text','label'=>__('notification letters allowed per hour (0 means unlimited)','wp-cerber'),'size'=>3));
 
 
 
 
211
 
212
  add_settings_section('pushit', __('Push notifications','wp-cerber'), 'cerber_sapi_section', CERBER_OPT_N);
213
  add_settings_field('pbtoken','Pushbullet access token','cerber_field_show',CERBER_OPT_N,'pushit',array('group'=>$group,'setting'=>'pbtoken','type'=>'text','size'=>60));
@@ -766,7 +773,14 @@ function cerber_time_select($args, $settings){
766
  Sanitizing users input for Main Settings
767
  */
768
  add_filter( 'pre_update_option_'.CERBER_OPT, 'cerber_sanitize_m', 10, 3 );
769
- function cerber_sanitize_m($new, $old, $option) { // $option added in WP 4.4.0
 
 
 
 
 
 
 
770
 
771
  $new['attempts'] = absint( $new['attempts'] );
772
  $new['period'] = absint( $new['period'] );
@@ -818,7 +832,7 @@ function cerber_sanitize_m($new, $old, $option) { // $option added in WP 4.4.0
818
  Sanitizing/checking user input for User tab settings
819
  */
820
  add_filter( 'pre_update_option_'.CERBER_OPT_U, 'cerber_sanitize_u', 10, 3 );
821
- function cerber_sanitize_u($new, $old, $option) { // $option added in WP 4.4.0
822
 
823
  $new['prohibited'] = cerber_text2array($new['prohibited'], ',', 'strtolower');
824
 
@@ -909,14 +923,15 @@ function cerber_sanitize_h($new, $old, $option) {
909
  if ( empty( $new['adminphp'] ) ) {
910
  $new['adminphp'] = 0;
911
  }
 
 
912
  if ( $new['adminphp'] != $old['adminphp'] ) {
913
- $result = cerber_htaccess_sync( $new );
914
- if ( $result === true ) {
915
  cerber_admin_message( 'The .htaccess file has been modified' );
916
  }
917
  else {
918
  $new['adminphp'] = $old['adminphp'];
919
- cerber_admin_notice( $result );
920
  }
921
  }
922
 
@@ -1088,6 +1103,7 @@ function cerber_ms_update() {
1088
  function cerber_get_defaults($field = null) {
1089
  $all_defaults = array(
1090
  CERBER_OPT => array(
 
1091
  'attempts' => 3,
1092
  'period' => 60,
1093
  'lockout' => 60,
@@ -1104,7 +1120,7 @@ function cerber_get_defaults($field = null) {
1104
  'nonusers' => 0,
1105
  'wplogin' => 0,
1106
  'noredirect' => 0,
1107
- 'page404' => 0,
1108
 
1109
  'loginpath' => '',
1110
  'loginnowp' => 0,
@@ -1169,6 +1185,7 @@ function cerber_get_defaults($field = null) {
1169
  CERBER_OPT_N => array(
1170
  'email' => '',
1171
  'emailrate' => 12,
 
1172
  'pbtoken' => '',
1173
  'pbdevice' => '',
1174
  'wreports-day' => '1', // workaround, see cerber_upgrade_options()
@@ -1294,18 +1311,18 @@ function cerber_get_options($option = '') {
1294
  *
1295
  * @return array|bool|mixed
1296
  */
1297
- function crb_get_settings($option = '') {
1298
- global $wpdb;
1299
- static $united;
1300
 
1301
  /**
1302
  * For some hosting environments it might be faster, e.g. Redis enabled
1303
  */
1304
- if ( defined( 'CERBER_WP_OPTIONS' ) ) {
1305
  return cerber_get_options( $option );
1306
  }
1307
 
1308
- if (!isset($united)) {
1309
 
1310
  $options = cerber_get_setting_list();
1311
  $in = 'IN ("' . implode( '","', $options ) . '")';
@@ -1406,7 +1423,9 @@ function cerber_load_defaults() {
1406
  }
1407
  }
1408
  $old = cerber_get_options();
1409
- if (!empty($old['loginpath'])) $save['loginpath'] = $old['loginpath'];
 
 
1410
  cerber_save_options( $save );
1411
  }
1412
 
67
  $tab='main'; // 'cerber-main' settings
68
  register_setting( 'cerberus-'.$tab, 'cerber-'.$tab );
69
 
70
+ add_settings_section( 'boot', __( 'Plugin initialization', 'wp-cerber' ), 'cerber_sapi_section', 'cerber-' . $tab );
71
+ add_settings_field('boot-mode',__('Load security engine','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'boot',array('group'=>$tab, 'option'=>'boot-mode', 'type'=>'select', 'set' => array(__('Legacy mode','wp-cerber'), __('Standard mode','wp-cerber'))));
72
+
73
  add_settings_section('cerber', __('Limit login attempts','wp-cerber'), 'cerber_sapi_section', 'cerber-' . $tab);
74
  add_settings_field('attempts',__('Attempts','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'cerber',array('group'=>$tab,'option'=>'attempts','type'=>'attempts'));
75
  add_settings_field('lockout',__('Lockout duration','wp-cerber'),'cerberus_field_show','cerber-'.$tab,'cerber',array('group'=>$tab,'option'=>'lockout','type'=>'text','label'=>__('minutes','wp-cerber'),'size'=>3));
211
  ) );
212
 
213
  add_settings_field('emailrate',__('Notification limit','wp-cerber'),'cerber_field_show',CERBER_OPT_N,'notify',array('group'=>$group,'setting'=>'emailrate','type'=>'text','label'=>__('notification letters allowed per hour (0 means unlimited)','wp-cerber'),'size'=>3));
214
+ add_settings_field( 'notify-new-ver', __( 'New version is available', 'wp-cerber' ), 'cerber_field_show', CERBER_OPT_N, 'notify', array( 'group' => $group,
215
+ 'setting' => 'notify-new-ver',
216
+ 'type' => 'checkbox'
217
+ ) );
218
 
219
  add_settings_section('pushit', __('Push notifications','wp-cerber'), 'cerber_sapi_section', CERBER_OPT_N);
220
  add_settings_field('pbtoken','Pushbullet access token','cerber_field_show',CERBER_OPT_N,'pushit',array('group'=>$group,'setting'=>'pbtoken','type'=>'text','size'=>60));
773
  Sanitizing users input for Main Settings
774
  */
775
  add_filter( 'pre_update_option_'.CERBER_OPT, 'cerber_sanitize_m', 10, 3 );
776
+ function cerber_sanitize_m($new, $old, $option) {
777
+
778
+ $ret = cerber_set_boot_mode( $new['boot-mode'], $old['boot-mode'] );
779
+ if ( is_wp_error( $ret ) ) {
780
+ cerber_admin_notice( __( 'ERROR:', 'wp-cerber' ) . ' ' . $ret->get_error_message() );
781
+ cerber_admin_notice( __( 'Plugin initialization mode has not been changed', 'wp-cerber' ) );
782
+ $new['boot-mode'] = $old['boot-mode'];
783
+ }
784
 
785
  $new['attempts'] = absint( $new['attempts'] );
786
  $new['period'] = absint( $new['period'] );
832
  Sanitizing/checking user input for User tab settings
833
  */
834
  add_filter( 'pre_update_option_'.CERBER_OPT_U, 'cerber_sanitize_u', 10, 3 );
835
+ function cerber_sanitize_u($new, $old, $option) {
836
 
837
  $new['prohibited'] = cerber_text2array($new['prohibited'], ',', 'strtolower');
838
 
923
  if ( empty( $new['adminphp'] ) ) {
924
  $new['adminphp'] = 0;
925
  }
926
+
927
+ $sync = cerber_htaccess_sync( $new );
928
  if ( $new['adminphp'] != $old['adminphp'] ) {
929
+ if ( $sync === true ) {
 
930
  cerber_admin_message( 'The .htaccess file has been modified' );
931
  }
932
  else {
933
  $new['adminphp'] = $old['adminphp'];
934
+ cerber_admin_notice( $sync );
935
  }
936
  }
937
 
1103
  function cerber_get_defaults($field = null) {
1104
  $all_defaults = array(
1105
  CERBER_OPT => array(
1106
+ 'boot-mode' => 0,
1107
  'attempts' => 3,
1108
  'period' => 60,
1109
  'lockout' => 60,
1120
  'nonusers' => 0,
1121
  'wplogin' => 0,
1122
  'noredirect' => 0,
1123
+ 'page404' => 1,
1124
 
1125
  'loginpath' => '',
1126
  'loginnowp' => 0,
1185
  CERBER_OPT_N => array(
1186
  'email' => '',
1187
  'emailrate' => 12,
1188
+ 'notify-new-ver' => '1',
1189
  'pbtoken' => '',
1190
  'pbdevice' => '',
1191
  'wreports-day' => '1', // workaround, see cerber_upgrade_options()
1311
  *
1312
  * @return array|bool|mixed
1313
  */
1314
+ function crb_get_settings( $option = '' ) {
1315
+ global $wpdb;
1316
+ static $united;
1317
 
1318
  /**
1319
  * For some hosting environments it might be faster, e.g. Redis enabled
1320
  */
1321
+ if ( defined( 'CERBER_WP_OPTIONS' ) && CERBER_WP_OPTIONS ) {
1322
  return cerber_get_options( $option );
1323
  }
1324
 
1325
+ if ( ! isset( $united ) ) {
1326
 
1327
  $options = cerber_get_setting_list();
1328
  $in = 'IN ("' . implode( '","', $options ) . '")';
1423
  }
1424
  }
1425
  $old = cerber_get_options();
1426
+ if ( ! empty( $old['loginpath'] ) ) {
1427
+ $save['loginpath'] = $old['loginpath'];
1428
+ }
1429
  cerber_save_options( $save );
1430
  }
1431
 
whois.php CHANGED
@@ -201,7 +201,7 @@ function cerber_get_flag_html( $code ) {
201
  return '';
202
  }
203
  if ( ! isset( $assets_url ) ) {
204
- $assets_url = plugin_dir_url( CERBER_FILE ) . 'assets/';
205
  }
206
 
207
  return '<span style="padding-left: 24px; background: url(\'' . $assets_url . 'flags/' . strtolower( $code ) . '.gif\') no-repeat left;"></span>';
201
  return '';
202
  }
203
  if ( ! isset( $assets_url ) ) {
204
+ $assets_url = cerber_plugin_dir_url() . 'assets/';
205
  }
206
 
207
  return '<span style="padding-left: 24px; background: url(\'' . $assets_url . 'flags/' . strtolower( $code ) . '.gif\') no-repeat left;"></span>';
wp-cerber.php CHANGED
@@ -1,4795 +1,51 @@
1
- <?php
2
- /*
3
- Plugin Name: WP Cerber Security & Antispam
4
- Plugin URI: https://wpcerber.com
5
- Description: Protects site from brute force attacks, bots and hackers. Antispam protection with the Cerber antispam engine and reCAPTCHA. Comprehensive control of user activity. Restrict login by IP access lists. Limit login attempts. Know more: <a href="https://wpcerber.com">wpcerber.com</a>.
6
- Author: Gregory
7
- Author URI: https://wpcerber.com
8
- Version: 6.2
9
- Text Domain: wp-cerber
10
- Domain Path: /languages
11
- Network: true
12
-
13
- Copyright (C) 2015-18 CERBER TECH INC., https://cerber.tech
14
- Copyright (C) 2015-18 Gregory Markov, https://wpcerber.com
15
-
16
- Licenced under the GNU GPL.
17
-
18
- This program is free software; you can redistribute it and/or modify
19
- it under the terms of the GNU General Public License as published by
20
- the Free Software Foundation; either version 3 of the License, or
21
- (at your option) any later version.
22
-
23
- This program is distributed in the hope that it will be useful,
24
- but WITHOUT ANY WARRANTY; without even the implied warranty of
25
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26
- GNU General Public License for more details.
27
-
28
- You should have received a copy of the GNU General Public License
29
- along with this program; if not, write to the Free Software
30
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
31
-
32
- */
33
- /*
34
-
35
-
36
-
37
- ▄████▄ ▓█████ ██▀███ ▄▄▄▄ ▓█████ ██▀███
38
- ▒██▀ ▀█ ▓█ ▀ ▓██ ▒ ██▒ ▓█████▄ ▓█ ▀ ▓██ ▒ ██▒
39
- ▒▓█ ▄ ▒███ ▓██ ░▄█ ▒ ▒██▒ ▄██ ▒███ ▓██ ░▄█ ▒
40
- ▒▓▓▄ ▄██▒ ▒▓█ ▄ ▒██▀▀█▄ ▒██░█▀ ▒▓█ ▄ ▒██▀▀█▄
41
- ▒ ▓███▀ ░ ░▒████▒ ░██▓ ▒██▒ ░▓█ ▀█▓ ░▒████▒ ░██▓ ▒██▒
42
- ░▒ ▒ ░ ░░ ▒░ ░ ░ ▒▓ ░▒▓░ ░▒▓███▀▒ ░░ ▒░ ░ ░ ▒▓ ░▒▓░
43
- ░ ▒ ░ ░ ░ ░▒ ▒░ ▒░▒ ░ ░ ░ ░ ░▒ ░ ▒░
44
- ░ ░ ░░ ░ ░ ░ ░ ░░ ░
45
- ░ ░ ░ ░ ░ ░ ░ ░
46
- ░ ░
47
-
48
-
49
-
50
-
51
- *========================================================================*
52
- | |
53
- | ATTENTION! Do not change or edit this file! |
54
- | |
55
- *========================================================================*
56
-
57
- */
58
-
59
- // If this file is called directly, abort executing.
60
- if ( ! defined( 'WPINC' ) ) {
61
- exit;
62
- }
63
-
64
- define( 'CERBER_VER', '6.2' );
65
- define( 'CERBER_LOG_TABLE', 'cerber_log' );
66
- define( 'CERBER_TRAF_TABLE', 'cerber_traffic' );
67
- define( 'CERBER_ACL_TABLE', 'cerber_acl' );
68
- define( 'CERBER_BLOCKS_TABLE', 'cerber_blocks' );
69
- define( 'CERBER_LAB_TABLE', 'cerber_lab' );
70
- define( 'CERBER_LAB_IP_TABLE', 'cerber_lab_ip' );
71
- define( 'CERBER_LAB_NET_TABLE', 'cerber_lab_net' );
72
- define( 'CERBER_GEO_TABLE', 'cerber_countries' );
73
-
74
- define( 'WP_LOGIN_SCRIPT', 'wp-login.php' );
75
- define( 'WP_REG_URI', 'wp-register.php' );
76
- define( 'WP_XMLRPC_SCRIPT', 'xmlrpc.php' );
77
- define( 'WP_TRACKBACK_SCRIPT', 'wp-trackback.php' );
78
- define( 'WP_PING_SCRIPT', 'wp-trackback.php' );
79
- define( 'WP_SIGNUP_SCRIPT', 'wp-signup.php' );
80
-
81
- define( 'GOO_RECAPTCHA_URL', 'https://www.google.com/recaptcha/api/siteverify' );
82
-
83
- define( 'CERBER_REQ_PHP', '5.3.0' );
84
- define( 'CERBER_REQ_WP', '4.4' );
85
- define( 'CERBER_FILE', __FILE__ );
86
- define( 'CERBER_TECH', 'https://cerber.tech/' );
87
-
88
- require_once( dirname( __FILE__ ) . '/cerber-pluggable.php' );
89
- require_once( dirname( __FILE__ ) . '/common.php' );
90
- require_once( dirname( __FILE__ ) . '/settings.php' );
91
- require_once( dirname( __FILE__ ) . '/cerber-lab.php' );
92
- require_once( dirname( __FILE__ ) . '/whois.php' );
93
- require_once( dirname( __FILE__ ) . '/jetflow.php' );
94
- require_once( dirname( __FILE__ ) . '/cerber-news.php' );
95
-
96
- if ( defined( 'WP_ADMIN' ) || defined( 'WP_NETWORK_ADMIN' ) ) {
97
- // Load dashboard stuff
98
- require_once( dirname( __FILE__ ) . '/dashboard.php' );
99
- }
100
-
101
-
102
- // Critical stuff that must be executed first ==================================================
103
-
104
- cerber_request_time();
105
-
106
- cerber_upgrade_all();
107
-
108
- cerber_beast();
109
-
110
- $antibot = cerber_antibot_gene();
111
- if ( $antibot && ! empty( $antibot[1] ) ) {
112
- foreach ( $antibot[1] as $item ) {
113
- setcookie( $item[0], $item[1], time() + 3600, COOKIEPATH );
114
- }
115
- }
116
-
117
-
118
- // =============================================================================================
119
-
120
- class WP_Cerber {
121
- private $remote_ip;
122
- private $session_id;
123
- private $status = null;
124
- private $options;
125
- private $locked = null; // IP has been locked out
126
-
127
- private $recaptcha = null; // Can recaptcha be verified with a current request
128
- private $recaptcha_verified = null; // Is recaptcha successfully verified with a current request
129
- public $recaptcha_here = null; // Is recaptcha widget enabled on the currently displayed page
130
-
131
- public $garbage = false; // Garbage has been deleted
132
-
133
- final function __construct() {
134
-
135
- $this->session_id = substr(str_shuffle('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'), 0, 24);
136
-
137
- // Load settings with filling missing (not-set) array keys
138
- $this->options = cerber_get_options();
139
- $keys = array();
140
- //$defaults = array();
141
- foreach ( cerber_get_defaults() as $item ) {
142
- $keys = array_merge( $keys, array_keys( $item ) );
143
- //$defaults = array_merge( $defaults, $item );
144
- }
145
- foreach ( $keys as $key ) {
146
- if ( ! isset( $this->options[ $key ] ) ) {
147
- $this->options[ $key ] = null;
148
- }
149
- }
150
-
151
- if ( defined( 'CERBER_IP_KEY' ) ) {
152
- $this->remote_ip = filter_var( $_SERVER[ CERBER_IP_KEY ], FILTER_VALIDATE_IP );
153
- }
154
- elseif ( $this->options['proxy'] && isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
155
- $list = explode( ',', $_SERVER['HTTP_X_FORWARDED_FOR'] );
156
- foreach ( $list as $maybe_ip ) {
157
- $this->remote_ip = filter_var( trim( $maybe_ip ), FILTER_VALIDATE_IP );
158
- if ( $this->remote_ip ) {
159
- break;
160
- }
161
- }
162
- if ( ! $this->remote_ip && isset( $_SERVER['HTTP_X_REAL_IP'] ) ) {
163
- $this->remote_ip = filter_var( $_SERVER['HTTP_X_REAL_IP'], FILTER_VALIDATE_IP );
164
- }
165
- } else {
166
- if ( isset( $_SERVER['REMOTE_ADDR'] ) ) {
167
- $this->remote_ip = $_SERVER['REMOTE_ADDR'];
168
- } elseif ( isset( $_SERVER['HTTP_X_REAL_IP'] ) ) {
169
- $this->remote_ip = $_SERVER['HTTP_X_REAL_IP'];
170
- } elseif ( isset( $_SERVER['HTTP_CLIENT_IP'] ) ) {
171
- $this->remote_ip = $_SERVER['HTTP_CLIENT_IP'];
172
- } elseif ( isset( $_SERVER['SERVER_ADDR'] ) ) {
173
- $this->remote_ip = $_SERVER['SERVER_ADDR'];
174
- }
175
- $this->remote_ip = filter_var( $this->remote_ip, FILTER_VALIDATE_IP );
176
- }
177
- // No IP address was found? Roll back to localhost.
178
- if ( ! $this->remote_ip ) {
179
- $this->remote_ip = '127.0.0.1';
180
- } // including WP-CLI, other way is: if defined('WP_CLI')
181
-
182
- $this->remote_ip = cerber_short_ipv6( $this->remote_ip );
183
-
184
- $this->reCaptchaInit();
185
-
186
- $this->deleteGarbage();
187
-
188
- // Condition to check reCAPTCHA
189
-
190
- add_action( 'login_init', array( $this, 'reCaptchaNow' ) );
191
-
192
- }
193
-
194
- // TODO: replace it with cerber_get_remote_ip()
195
- final public function getRemoteIp() {
196
- return $this->remote_ip;
197
- }
198
-
199
- final public function getSessionID() {
200
- return $this->session_id;
201
- }
202
-
203
- final public function getStatus() {
204
- if (isset($this->status)) return $this->status;
205
-
206
- $this->status = 0; // Default
207
-
208
- if ( cerber_is_citadel() ) {
209
- $this->status = 3;
210
- }
211
- else {
212
- //if ( ! cerber_is_allowed( $this->remote_ip ) ) {
213
- if ( cerber_block_check( $this->remote_ip ) ) {
214
- $this->status = 2;
215
- }
216
- else {
217
- $tag = cerber_acl_check( $this->remote_ip );
218
- if ( $tag == 'W' ) {
219
- //$this->status = 4;
220
- }
221
- elseif ( $tag == 'B' || lab_is_blocked($this->remote_ip, false)) {
222
- $this->status = 1;
223
- }
224
- }
225
- }
226
-
227
- return $this->status;
228
- }
229
-
230
- /*
231
- Return Error message in context
232
- */
233
- final public function getErrorMsg() {
234
- $status = $this->getStatus();
235
- switch ( $status ) {
236
- case 1:
237
- case 3:
238
- return apply_filters( 'cerber_msg_blocked', __( 'You are not allowed to log in. Ask your administrator for assistance.', 'wp-cerber' ) , $status);
239
- case 2:
240
- $block = cerber_get_block();
241
- $min = 1 + ( $block->block_until - time() ) / 60;
242
-
243
- return apply_filters( 'cerber_msg_reached',
244
- sprintf( __( 'You have reached the login attempts limit. Please try again in %d minutes.', 'wp-cerber' ), $min ),
245
- $min );
246
- break;
247
- default:
248
- return '';
249
- }
250
- }
251
-
252
- /*
253
- Return Remain message in context
254
- */
255
- final public function getRemainMsg() {
256
- $acl = !$this->options['limitwhite'];
257
- $remain = cerber_get_remain_count($this->remote_ip, $acl);
258
- if ( $remain < $this->options['attempts'] ) {
259
- if ( $remain == 0 ) {
260
- $remain = 1; // with some settings or when lockout was manually removed, we need to have 1 attempt.
261
- }
262
- return apply_filters( 'cerber_msg_remain',
263
- sprintf( _n( 'You have only one attempt remaining.', 'You have %d attempts remaining.', $remain, 'wp-cerber' ), $remain ),
264
- $remain );
265
- }
266
-
267
- return false;
268
- }
269
-
270
- final public function getSettings( $name = null ) {
271
- if ( ! empty( $name ) ) {
272
- if ( isset( $this->options[ $name ] ) ) {
273
- return $this->options[ $name ];
274
- } else {
275
- return false;
276
- }
277
- }
278
-
279
- return $this->options;
280
- }
281
-
282
- /*
283
- final public function isProhibited( $username ) {
284
- if ( empty( $this->options['prohibited'] ) ) {
285
- return false;
286
- }
287
-
288
- return in_array( $username, (array) $this->options['prohibited'] );
289
- }*/
290
-
291
- /**
292
- * Adding reCAPTCHA widgets
293
- *
294
- */
295
- final public function reCaptchaInit(){
296
-
297
- if ( $this->status == 4 || empty( $this->options['sitekey'] ) || empty( $this->options['secretkey'] )) return;
298
-
299
- // Native WP forms
300
- add_action( 'login_form', function () {
301
- global $wp_cerber;
302
- $wp_cerber->reCaptcha( 'widget', 'recaplogin' );
303
- } );
304
- add_filter( 'login_form_middle', function ( $value ) {
305
- global $wp_cerber;
306
- $value .= $wp_cerber->reCaptcha( 'widget', 'recaplogin', false );
307
- return $value;
308
- });
309
- add_action( 'lostpassword_form', function () {
310
- global $wp_cerber;
311
- $wp_cerber->reCaptcha( 'widget', 'recaplost' );
312
- } );
313
- add_action( 'register_form', function () {
314
- global $wp_cerber;
315
- if ( !did_action( 'woocommerce_register_form_start' ) ) {
316
- $wp_cerber->reCaptcha( 'widget', 'recapreg' );
317
- }
318
- } );
319
-
320
- // Support for WooCommerce forms: @since 3.8
321
- add_action( 'woocommerce_login_form', function () {
322
- global $wp_cerber;
323
- $wp_cerber->reCaptcha( 'widget', 'recapwoologin' );
324
- } );
325
- add_action( 'woocommerce_lostpassword_form', function () {
326
- global $wp_cerber;
327
- $wp_cerber->reCaptcha( 'widget', 'recapwoolost' );
328
- } );
329
- add_action( 'woocommerce_register_form', function () {
330
- global $wp_cerber;
331
- if ( ! did_action( 'woocommerce_register_form_start' ) ) {
332
- return;
333
- }
334
- $wp_cerber->reCaptcha( 'widget', 'recapwooreg' );
335
- } );
336
- add_filter( 'woocommerce_process_login_errors', function ( $validation_error ) {
337
- global $wp_cerber;
338
- //$wp_cerber->reCaptchaNow();
339
- if ( ! $wp_cerber->reCaptchaValidate('woologin', true) ) {
340
-
341
- return new WP_Error( 'incorrect_recaptcha', $wp_cerber->reCaptchaMsg('woocommerce-login'));
342
- }
343
- return $validation_error;
344
- });
345
- add_filter( 'allow_password_reset', function ( $var ) { // Note: 'allow_password_reset' also is fired in WP itself
346
- global $wp_cerber;
347
- if ( isset( $_POST['wc_reset_password'] ) && did_action( 'woocommerce_init' )) {
348
- //$wp_cerber->reCaptchaNow();
349
- if ( ! $wp_cerber->reCaptchaValidate( 'woolost' , true) ) {
350
-
351
- return new WP_Error( 'incorrect_recaptcha', $wp_cerber->reCaptchaMsg('woocommerce-lost'));
352
- }
353
- }
354
- return $var;
355
- });
356
- add_filter( 'woocommerce_process_registration_errors', function ( $validation_error ) {
357
- global $wp_cerber;
358
- //$wp_cerber->reCaptchaNow();
359
- if ( ! $wp_cerber->reCaptchaValidate('wooreg' , true) ) {
360
-
361
- return new WP_Error( 'incorrect_recaptcha', $wp_cerber->reCaptchaMsg('woocommerce-register'));
362
- }
363
- return $validation_error;
364
- });
365
-
366
- }
367
-
368
- /**
369
- * Generates reCAPTCHA HTML
370
- *
371
- * @param string $part 'style' or 'widget'
372
- * @param null $option what plugin setting must be set to show the reCAPTCHA
373
- * @param bool $echo if false, return the code, otherwise show it
374
- *
375
- * @return null|string
376
- */
377
- final public function reCaptcha( $part = '', $option = null, $echo = true ) {
378
- if ( $this->status == 4 || empty( $this->options['sitekey'] ) || empty( $this->options['secretkey'] )
379
- || ( $option && empty( $this->options[ $option ] ) )
380
- ) {
381
- return null;
382
- }
383
-
384
- $sitekey = $this->options['sitekey'];
385
- $ret = '';
386
-
387
- switch ( $part ) {
388
- case 'style': // for default login WP form only - fit it in width nicely.
389
- ?>
390
- <style type="text/css" media="all">
391
- #rc-imageselect, .g-recaptcha {
392
- transform: scale(0.9);
393
- -webkit-transform: scale(0.9);
394
- transform-origin: 0 0;
395
- -webkit-transform-origin: 0 0;
396
- }
397
-
398
- .g-recaptcha {
399
- margin: 16px 0 20px 0;
400
- }
401
- </style>
402
- <?php
403
- break;
404
- case 'widget':
405
- if ( ! empty( $this->options[ $option ] ) ) {
406
- $this->recaptcha_here = true;
407
-
408
- //if ($this->options['invirecap']) $ret = '<div data-size="invisible" class="g-recaptcha" data-sitekey="' . $sitekey . '" data-callback="now_submit_the_form" id="cerber-recaptcha" data-badge="bottomright"></div>';
409
- if ($this->options['invirecap']) {
410
- $ret = '<span class="cerber-form-marker"></span><div data-size="invisible" class="g-recaptcha" data-sitekey="' . $sitekey . '" data-callback="now_submit_the_form" id="cerber-recaptcha" data-badge="bottomright"></div>';
411
- }
412
- else $ret = '<span class="cerber-form-marker"></span><div class="g-recaptcha" data-sitekey="' . $sitekey . '" data-callback="form_button_enabler" id="cerber-recaptcha"></div>';
413
-
414
- //$ret = '<span class="cerber-form-marker g-recaptcha"></span>';
415
-
416
- }
417
- break;
418
- }
419
- if ( $echo ) {
420
- echo $ret;
421
- $ret = null;
422
- }
423
-
424
- return $ret;
425
- /*
426
- <script type="text/javascript">
427
- var onloadCallback = function() {
428
- //document.getElementById("wp-submit").disabled = true;
429
- grecaptcha.render("c-recaptcha", {"sitekey" : "<?php echo $sitekey; ?>" });
430
- //document.getElementById("wp-submit").disabled = false;
431
- };
432
- </script>
433
- <script src = "https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit&hl=<?php echo $lang; ?>" async defer></script>
434
- */
435
- }
436
-
437
- /**
438
- * Validate reCAPTCHA by calling Google service
439
- *
440
- * @param string $form Form ID (slug)
441
- * @param boolean $force Force validate without pre-checks
442
- *
443
- * @return bool true on success false on failure
444
- */
445
- final public function reCaptchaValidate($form = null, $force = false) {
446
- if (!$force) {
447
- if ( ! $this->recaptcha || $this->status == 4 ) {
448
- return true;
449
- }
450
- }
451
-
452
- if ($this->recaptcha_verified != null) return $this->recaptcha_verified;
453
-
454
- if ( $form == 'comment' && $this->options['recapcomauth'] && is_user_logged_in()) return true;
455
-
456
- if ( ! $form ) {
457
- $form = isset( $_REQUEST['action'] ) ? $_REQUEST['action'] : 'login';
458
- }
459
-
460
- $forms = array( // known pairs: form => specific plugin setting
461
- 'lostpassword' => 'recaplost',
462
- 'register' => 'recapreg',
463
- 'login' => 'recaplogin',
464
- 'comment' => 'recapcom',
465
- 'woologin' => 'recapwoologin',
466
- 'woolost' => 'recapwoolost',
467
- 'wooreg' => 'recapwooreg',
468
- );
469
-
470
- if ( isset( $forms[ $form ] ) ) {
471
- if ( empty( $this->options[ $forms[ $form ] ] ) ) {
472
- return true; // no validation is required
473
- }
474
- }
475
- else {
476
- return true; // we don't know this form
477
- }
478
-
479
- if ( empty( $_POST['g-recaptcha-response'] ) ) {
480
- $this->reCaptchaFailed($form);
481
- return false;
482
- }
483
-
484
- $result = $this->reCaptchaRequest($_POST['g-recaptcha-response']);
485
- if ( ! $result ) {
486
- cerber_log( 42 );
487
- return false;
488
- }
489
-
490
- $result = json_decode( $result );
491
- $result = obj_to_arr_deep( $result );
492
-
493
- if ( ! empty( $result['success'] ) ) {
494
- $this->recaptcha_verified = true;
495
- return true;
496
- }
497
- $this->recaptcha_verified = false;
498
-
499
- if ( ! empty( $result['error-codes'] ) ) {
500
- if ( in_array( 'invalid-input-secret', (array) $result['error-codes'] ) ) {
501
- cerber_log( 41 );
502
- }
503
- }
504
-
505
- $this->reCaptchaFailed($form);
506
-
507
- return false;
508
- }
509
-
510
- final function reCaptchaFailed($context = '') {
511
- cerber_log( 40 );
512
- if ($this->options['recaptcha-period'] && $this->options['recaptcha-number'] && $this->options['recaptcha-within']) {
513
- $remain = cerber_get_remain_count($this->remote_ip , true, 40, $this->options['recaptcha-number'], $this->options['recaptcha-within']);
514
- if ($remain < 1) cerber_block_add( $this->remote_ip, 5 );
515
- }
516
- }
517
-
518
- /**
519
- * A form with possible reCAPTCHA has been submitted.
520
- * Allow to process reCAPTCHA by setting a global flag.
521
- * Must be called before reCaptchaValidate();
522
- *
523
- */
524
- final public function reCaptchaNow() {
525
- if ( cerber_is_http_post() && $this->options['sitekey'] && $this->options['secretkey'] ) {
526
- $this->recaptcha = true;
527
- }
528
- }
529
-
530
- /**
531
- * Make a request to the Google reCaptcha web service
532
- *
533
- * @param string $response Google specific field from the submitted form (widget)
534
- *
535
- * @return bool|string Response of the Google service or false on failure
536
- */
537
- final public function reCaptchaRequest($response = ''){
538
-
539
- if (!$response) {
540
- if (!empty($_POST['g-recaptcha-response'])) $response = $_POST['g-recaptcha-response'];
541
- else return false;
542
- }
543
-
544
- $curl = @curl_init(); // @since 4.32
545
- if (!$curl) {
546
- cerber_admin_notice(__( 'ERROR:', 'wp-cerber' ) .' Unable to initialize cURL');
547
- return false;
548
- }
549
-
550
- $opt = curl_setopt_array($curl, array(
551
- CURLOPT_URL => GOO_RECAPTCHA_URL,
552
- CURLOPT_POST => true,
553
- CURLOPT_POSTFIELDS => array( 'secret' => $this->options['secretkey'], 'response' => $response ),
554
- CURLOPT_RETURNTRANSFER => true,
555
- ));
556
-
557
- if (!$opt) {
558
- cerber_admin_notice(__( 'ERROR:', 'wp-cerber' ) .' '. curl_error($curl));
559
- curl_close($curl);
560
- return false;
561
- }
562
-
563
- $result = curl_exec($curl);
564
- if (!$result) {
565
- cerber_admin_notice(__( 'ERROR:', 'wp-cerber' ) .' '. curl_error($curl));
566
- $result = false;
567
- }
568
- curl_close($curl);
569
-
570
- return $result;
571
-
572
- }
573
-
574
- final public function reCaptchaMsg($context = null){
575
- return apply_filters( 'cerber_msg_recaptcha', __( 'Human verification failed. Please click the square box in the reCAPTCHA block below.', 'wp-cerber' ), $context);
576
- }
577
-
578
- final public function setLocked() {
579
- if ( ! isset( $this->locked ) ) {
580
- $this->locked = 1;
581
- }
582
- }
583
-
584
- final public function isLocked() {
585
- if ( ! empty( $this->locked ) ) {
586
- return 1;
587
- }
588
- return 0;
589
- }
590
-
591
- final public function deleteGarbage() {
592
- global $wpdb;
593
- if ( $this->garbage ) {
594
- return;
595
- }
596
- $wpdb->query( 'DELETE FROM ' . CERBER_BLOCKS_TABLE . ' WHERE block_until < ' . time() );
597
- $this->garbage = true;
598
- }
599
- }
600
-
601
- global $wp_cerber;
602
- //$wp_cerber = new WP_Cerber();
603
- $wp_cerber = get_wp_cerber();
604
-
605
- /**
606
- * Return correct WP_Cerber object
607
- * Set global $wp_cerber
608
- *
609
- * @return WP_Cerber
610
- * @since 6.0
611
- */
612
- function get_wp_cerber(){
613
- global $wp_cerber;
614
-
615
- if ( ! is_object( $wp_cerber ) || !($wp_cerber instanceof WP_Cerber)) {
616
- $wp_cerber = new WP_Cerber();
617
- }
618
-
619
- return $wp_cerber;
620
- }
621
-
622
- /**
623
- *
624
- * Initialize Cerber Security
625
- *
626
- */
627
- add_action( 'plugins_loaded', function () {
628
-
629
- get_wp_cerber();
630
-
631
- load_plugin_textdomain( 'wp-cerber', false, basename( dirname( __FILE__ ) ) . '/languages' );
632
-
633
- /* @since 5.8.8
634
- if ( ! cerber_check_groove() && ! cerber_is_allowed() ) {
635
- wp_clear_auth_cookie();
636
- }*/
637
-
638
- cerber_init_cron();
639
-
640
- __('> > > Translator of WP Cerber? To get the PRO license for free, drop your contacts here: https://wpcerber.com/contact/','wp-cerber');
641
-
642
- }, 1000 );
643
-
644
- /**
645
- * Some additional tasks...
646
- *
647
- */
648
- add_action( 'shutdown', function () {
649
- global $wpdb, $wp_cerber, $cerber_logged, $cerber_status;
650
-
651
- if ( empty( $cerber_logged ) ) {
652
- return;
653
- }
654
-
655
- // Multiple different malicious activities
656
- $black = crb_get_activity_set('black');
657
- $no_good = array_intersect( $black, $cerber_logged );
658
- if ( ! empty( $no_good ) && cerber_is_allowed() ) {
659
- $ip = $wp_cerber->getRemoteIp();
660
- $in = implode( ',', $black );
661
- $range = time() - 600;
662
- $count = $wpdb->get_var( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE ip = "' . $ip . '" AND activity IN (' . $in . ') AND stamp > ' . $range );
663
- if ( $count >= 3 ) {
664
- cerber_soft_block_add( $ip, 7 );
665
- $cerber_status = 18;
666
- }
667
- }
668
-
669
- } );
670
-
671
- /*
672
- Display login form if Custom login URL has been requested
673
-
674
- */
675
- add_action( 'init', 'cerber_wp_login_page', 20 );
676
- //add_action( 'setup_theme', 'cerber_wp_login_page' ); // @since 5.05
677
- function cerber_wp_login_page() {
678
- if ( $path = crb_get_settings( 'loginpath' ) ) {
679
- if ( cerber_is_login_request() ) {
680
- if ( ! defined( 'DONOTCACHEPAGE' ) ) {
681
- define( 'DONOTCACHEPAGE', true ); // @since 5.7.6
682
- }
683
- require( ABSPATH . WP_LOGIN_SCRIPT ); // load default wp-login.php form
684
- exit;
685
- }
686
- }
687
- }
688
-
689
- /**
690
- * Check if the current HTTP request is a login/register/lost password page request
691
- *
692
- * @return bool
693
- */
694
- function cerber_is_login_request() {
695
- if ( $path = crb_get_settings( 'loginpath' ) ) {
696
- $request = $_SERVER['REQUEST_URI'];
697
- if ( $pos = strpos( $request, '?' ) ) {
698
- $request = substr( $request, 0, $pos - 1 ); // @since 4.8
699
- }
700
- $request = explode( '/', rtrim( $request, '/' ) );
701
- $request = end( $request ); // @since 4.8
702
- if ( $path == $request && ! cerber_is_rest_url() ) {
703
- return true;
704
- }
705
- }
706
- //elseif ( strtolower( cerber_parse_uri( true ) ) == WP_LOGIN_SCRIPT ) {
707
- elseif ( cerber_get_uri_script() == WP_LOGIN_SCRIPT ) {
708
- return true;
709
- }
710
-
711
- return false;
712
- }
713
-
714
- /*
715
- Create message to show it above login form for any simply GET
716
- */
717
- add_action( 'login_head', 'cerber_login_head' );
718
- function cerber_login_head() {
719
- global $error, $wp_cerber;
720
-
721
- if ( !$allowed = cerber_is_allowed() ) :
722
- ?>
723
- <style type="text/css" media="all">
724
- #logidnform {
725
- display: none;
726
- }
727
- </style>
728
- <?php
729
- endif;
730
-
731
- $wp_cerber->reCaptcha( 'style' );
732
-
733
- if ( !cerber_is_http_get() ) {
734
- return;
735
- }
736
- if ( ! cerber_can_msg() ) {
737
- return;
738
- }
739
- if ( ! $allowed ) {
740
- $error = $wp_cerber->getErrorMsg();
741
- }
742
- elseif ( $msg = $wp_cerber->getRemainMsg() ) {
743
- $error = $msg;
744
- }
745
- }
746
-
747
- /**
748
- * Control the process of authentication
749
- *
750
- * @since 2.9
751
- *
752
- */
753
- remove_filter( 'authenticate', 'wp_authenticate_username_password', 20 );
754
- add_filter( 'authenticate', 'cerber_auth_control', 20, 3 );
755
- function cerber_auth_control( $null, $username, $password ) {
756
- global $wp_cerber;
757
-
758
- if ( ! $wp_cerber->reCaptchaValidate() ) {
759
-
760
- return new WP_Error( 'incorrect_recaptcha',
761
- '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
762
- $wp_cerber->reCaptchaMsg('login'));
763
- }
764
-
765
- // Check for prohibited username
766
- //if ( $wp_cerber->isProhibited( $username ) ) {
767
- if ( cerber_is_prohibited( $username ) ) {
768
- cerber_log( 52, $username );
769
- cerber_block_add( null, 4, $username );
770
-
771
- // Create with message that is identical default WP
772
- return new WP_Error( 'incorrect_password', sprintf(
773
- __( '<strong>ERROR</strong>: The password you entered for the username %s is incorrect.' ),
774
- '<strong>' . $username . '</strong>'
775
- ) );
776
- }
777
- /*
778
- if ( lab_is_blocked($wp_cerber->getRemoteIp()) ) {
779
-
780
- // Create with message which is identical default WP
781
- return new WP_Error( 'incorrect_password', sprintf(
782
- __( '<strong>ERROR</strong>: The password you entered for the username %s is incorrect.' ),
783
- '<strong>' . $username . '</strong>'
784
- ) );
785
- }*/
786
-
787
- $user = wp_authenticate_username_password( $null, $username, $password );
788
-
789
- // @since 4.18 it is replacement for 'wp_login_failed' action hook
790
- // see WP function wp_authenticate()
791
- $ignore_codes = array( 'empty_username', 'empty_password', 'cerber_denied' );
792
- if ( is_wp_error( $user ) && ! in_array( $user->get_error_code(), $ignore_codes ) ) {
793
- cerber_login_failed( $username );
794
- }
795
-
796
- return $user;
797
- }
798
-
799
- /*
800
- Block authentication for an existing user if the remote IP is not allowed.
801
- Invoking in the 'wp_authenticate_username_password()'
802
- */
803
- add_filter( 'wp_authenticate_user', 'cerber_stop_authentication', 9999, 2 ); // fires after user found, with 'authenticate' filter
804
- function cerber_stop_authentication( $user, $password ) {
805
- global $wp_cerber, $cerber_status;
806
-
807
- $deny = false;
808
-
809
- if ( ! cerber_is_allowed() ) {
810
- $deny = true;
811
- }
812
- elseif ( ! cerber_geo_allowed( 'geo_login' ) ) {
813
- $cerber_status = 16;
814
- $deny = true;
815
- }
816
- elseif ( lab_is_blocked( $wp_cerber->getRemoteIp() ) ) {
817
- $cerber_status = 15;
818
- $deny = true;
819
- }
820
-
821
- if ( $deny ) {
822
- status_header( 403 );
823
- $error = new WP_Error();
824
- $error->add( 'cerber_wp_error', $wp_cerber->getErrorMsg() );
825
-
826
- return $error;
827
- }
828
-
829
- return $user;
830
- }
831
-
832
- /*
833
- * Handler for failed login attempts
834
- *
835
- */
836
- //add_action( 'wp_login_failed', 'cerber_login_failed' ); // @since 4.18
837
- function cerber_login_failed( $user_login ) {
838
- global $wpdb, $wp_cerber, $cerber_status;
839
- static $is_processed = false;
840
-
841
- if ( $is_processed ) return;
842
- $is_processed = true;
843
-
844
- $ip = $wp_cerber->getRemoteIp();
845
- $acl = cerber_acl_check( $ip );
846
- if ( ! cerber_get_user( $user_login ) ) {
847
- $no_user = true;
848
- }
849
- else {
850
- $no_user = false;
851
- }
852
-
853
- //cerber_failed_work($ip, $acl, $no_user, $user_login);
854
-
855
- //if ( ! $wp_cerber->isProcessed() ) {
856
- //if ( ! cerber_get_user( $user_login ) ) {
857
- // $no_user = true;
858
- //}
859
-
860
- $ac = 7;
861
-
862
- if ( $no_user ) {
863
- $ac = 51;
864
- }
865
- elseif ( ! cerber_is_allowed( $ip ) || $cerber_status == 15 || $cerber_status == 16 ) { // TODO should be refactored together with cerber_stop_authentication
866
- $ac = 53;
867
- }
868
- /*
869
- elseif ( $acl == 'B' ) {
870
- $ac = 14;
871
- }
872
- elseif ( lab_is_blocked($ip, false) ) {
873
- $ac = 53;
874
- }
875
- else {
876
- $ac = 53;
877
- }*/
878
-
879
- cerber_log( $ac, $user_login );
880
-
881
- //}
882
-
883
-
884
- // White? Stop further actions.
885
- if ( $acl == 'W' && !crb_get_settings( 'limitwhite' )) {
886
- return;
887
- }
888
-
889
- if ( crb_get_settings( 'usefile' ) ) {
890
- cerber_file_log( $user_login, $ip );
891
- }
892
-
893
- if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) { // Needs additional researching and, maybe, refactoring
894
- status_header( 403 );
895
- }
896
-
897
- // Blacklisted? No more actions are needed.
898
- if ( $acl == 'B' ) {
899
- return;
900
- }
901
-
902
- // Must the Citadel mode be activated?
903
- if ( $wp_cerber->getSettings( 'ciperiod' ) && ! cerber_is_citadel() ) {
904
- $range = time() - $wp_cerber->getSettings( 'ciperiod' ) * 60;
905
- $lockouts = $wpdb->get_var( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE activity IN (7,51,52) AND stamp > ' . $range );
906
- if ( $lockouts >= $wp_cerber->getSettings( 'cilimit' ) ) {
907
- cerber_enable_citadel();
908
- }
909
- }
910
-
911
- if ( $no_user && $wp_cerber->getSettings( 'nonusers' ) ) {
912
- cerber_block_add( $ip, 3, $user_login); // @since 5.7
913
- }
914
- elseif ( cerber_get_remain_count($ip, false) < 1 ) { //Limit on the number of login attempts is reached
915
- cerber_block_add( $ip, 1, '', null, false);
916
- }
917
-
918
- }
919
-
920
- /**
921
- * Do the work with failed/blocked attempt
922
- *
923
- * @param $ip
924
- * @param $acl
925
- * @param $user_login
926
- */
927
- function cerber_failed_work($ip, $acl, $no_user, $user_login){
928
- global $wpdb, $wp_cerber;
929
-
930
- // White? Stop further actions.
931
- if ( $acl == 'W' && !$wp_cerber->getSettings( 'limitwhite' )) {
932
- return;
933
- }
934
-
935
- if ( $wp_cerber->getSettings( 'usefile' ) ) {
936
- cerber_file_log( $user_login, $ip );
937
- }
938
-
939
- if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) { // Needs additional researching and, maybe, refactoring
940
- status_header( 403 );
941
- }
942
-
943
- // Blacklisted? No more actions are needed.
944
- if ( $acl == 'B' ) {
945
- return;
946
- }
947
-
948
- // Must the Citadel mode be activated?
949
- if ( $wp_cerber->getSettings( 'ciperiod' ) && ! cerber_is_citadel() ) {
950
- $range = time() - $wp_cerber->getSettings( 'ciperiod' ) * 60;
951
- $lockouts = $wpdb->get_var( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE activity IN (7,51,52) AND stamp > ' . $range );
952
- if ( $lockouts >= $wp_cerber->getSettings( 'cilimit' ) ) {
953
- cerber_enable_citadel();
954
- }
955
- }
956
-
957
- if ( $no_user && $wp_cerber->getSettings( 'nonusers' ) ) {
958
- cerber_block_add( $ip, 3, $user_login );
959
- }
960
- elseif ( cerber_get_remain_count($ip, false) <= 1 ) { //Limit on the number of login attempts is reached
961
- cerber_block_add( $ip, 1, '', null, false);
962
- }
963
- }
964
-
965
- // Registration -----------------------------------------------------------------------
966
-
967
- function cerber_is_registration_prohibited( $sanitized_user_login ) {
968
- global $wp_cerber, $cerber_status;
969
-
970
- $code = null;
971
- $msg = null;
972
-
973
- if (crb_is_reg_limit_reached()){
974
- $cerber_status = 17;
975
- cerber_log(54);
976
- $code = 'ip_denied';
977
- $msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
978
- apply_filters( 'cerber_msg_denied', __( 'You are not allowed to register.', 'wp-cerber' ), 'register' );
979
- }
980
- elseif ( cerber_is_bot('botsreg') ) {
981
- cerber_log(54); // TODO should be separate code to detect bot activity?
982
- $code = 'bot_detected';
983
- $msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
984
- apply_filters( 'cerber_msg_denied', __( 'You are not allowed to register.', 'wp-cerber' ), 'register' );
985
- }
986
- elseif ( ! $wp_cerber->reCaptchaValidate() ) {
987
- $code = 'incorrect_recaptcha';
988
- $msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
989
- $wp_cerber->reCaptchaMsg('register');
990
- }
991
- elseif ( cerber_is_prohibited( $sanitized_user_login ) ) {
992
- $code = 'prohibited_login';
993
- $msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
994
- apply_filters( 'cerber_msg_prohibited', __( 'Username is not allowed. Please choose another one.', 'wp-cerber' ), 'register' );
995
- }
996
- elseif ( !cerber_is_allowed() || lab_is_blocked($wp_cerber->getRemoteIp()) ) {
997
- cerber_log(54);
998
- $code = 'ip_denied';
999
- $msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
1000
- apply_filters( 'cerber_msg_denied', __( 'You are not allowed to register.', 'wp-cerber' ), 'register' );
1001
- }
1002
- elseif ( ! cerber_geo_allowed( 'geo_register' ) ) {
1003
- $cerber_status = 16; // TODO: refactor cerber_log, include this status as a second parameter
1004
- cerber_log(54); // TODO should be separate code?
1005
- $code = 'country_denied';
1006
- $msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
1007
- apply_filters( 'cerber_msg_denied', __( 'You are not allowed to register.', 'wp-cerber' ), 'register' );
1008
- }
1009
-
1010
- if ( $code ) {
1011
- return array( $code, $msg );
1012
- }
1013
-
1014
- return null;
1015
- }
1016
-
1017
- /**
1018
- * Limit on user registrations per IP
1019
- *
1020
- * @return bool
1021
- */
1022
- function crb_is_reg_limit_reached() {
1023
- global $wpdb, $wp_cerber;
1024
-
1025
- if ( ! $wp_cerber->getSettings( 'reglimit_min' ) || ! $wp_cerber->getSettings( 'reglimit_num' ) ) {
1026
- return false;
1027
- }
1028
-
1029
- if ( crb_acl_is_white() ) {
1030
- return false;
1031
- }
1032
-
1033
- $ip = $wp_cerber->getRemoteIp();
1034
- $stamp = absint( time() - 60 * $wp_cerber->getSettings( 'reglimit_min' ) );
1035
- $count = $wpdb->get_var( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE ip = "' . $ip . '" AND activity = 2 AND stamp > ' . $stamp );
1036
- if ( $count > $wp_cerber->getSettings( 'reglimit_num' ) ) {
1037
- lab_save_push( $ip, 344, '' );
1038
- return true;
1039
- }
1040
-
1041
- return false;
1042
- }
1043
-
1044
- // Fires in register_new_user()
1045
- add_filter( 'registration_errors', 'cerber_pre_new_user', 10, 3 );
1046
- function cerber_pre_new_user( $errors, $sanitized_user_login, $user_email ) {
1047
- global $wp_cerber, $cerber_status;
1048
-
1049
- $prohibited = cerber_is_registration_prohibited( $sanitized_user_login );
1050
-
1051
- if ($prohibited){
1052
- return new WP_Error($prohibited[0], $prohibited[1]);
1053
- }
1054
-
1055
- return $errors;
1056
- }
1057
-
1058
- // @since 5.3
1059
- // Fires in wp_insert_user()
1060
- add_filter( 'pre_user_login', function ( $sanitized_user_login ) {
1061
-
1062
- if ( cerber_is_registration_prohibited( $sanitized_user_login ) ) {
1063
- return null;
1064
- }
1065
-
1066
- /*
1067
- if ( ! cerber_is_allowed() ) {
1068
- cerber_log( 54 );
1069
-
1070
- return null;
1071
- }
1072
- if ( ! cerber_geo_allowed( 'geo_register' ) ) {
1073
- $cerber_status = 16;
1074
- cerber_log( 54 );
1075
-
1076
- return null;
1077
- }
1078
- */
1079
- return $sanitized_user_login;
1080
- }, 9999 );
1081
-
1082
- // Filter out prohibited usernames
1083
- add_filter( 'illegal_user_logins', function () {
1084
- return (array) crb_get_settings( 'prohibited' );
1085
- }, 9999 );
1086
-
1087
- add_filter( 'option_users_can_register', function ( $value ) {
1088
- //if ( ! cerber_is_allowed() || !cerber_geo_allowed( 'geo_register' )) {
1089
- if ( ! cerber_is_allowed() || crb_is_reg_limit_reached() ) {
1090
- return false;
1091
- }
1092
-
1093
- return $value;
1094
- }, 9999 );
1095
-
1096
- // Lost password form --------------------------------------------------------------------
1097
-
1098
- /**
1099
- * Validate reCAPTCHA for the WordPress lost password form
1100
- */
1101
- add_action( 'login_form_' . 'lostpassword', 'cerber_lost_captcha' );
1102
- function cerber_lost_captcha() {
1103
- global $wp_cerber, $cerber_lost;
1104
- if ( ! $wp_cerber->reCaptchaValidate() ) {
1105
- $_POST['user_login'] = null; // workaround due to lack of any way to control lost password form
1106
- $cerber_lost = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' . $wp_cerber->reCaptchaMsg('lostpassword');
1107
- }
1108
- }
1109
- /**
1110
- * Display message on the WordPress lost password form screen
1111
- */
1112
- add_action( 'lostpassword_form', 'cerber_lost_show_msg' );
1113
- function cerber_lost_show_msg() {
1114
- global $cerber_lost;
1115
- if ( ! $cerber_lost ) {
1116
- return;
1117
- }
1118
- ?>
1119
- <script type="text/javascript">
1120
- //document.getElementById('login_error').style.visibility = "hidden";
1121
- document.getElementById('login_error').innerHTML = "<?php echo $cerber_lost; ?>";
1122
- </script>
1123
- <?php
1124
- }
1125
-
1126
-
1127
- // Comments (commenting) section ----------------------------------------------------------
1128
-
1129
- /**
1130
- * If a comment must be marked as spam
1131
- *
1132
- */
1133
- add_filter( 'pre_comment_approved', function ( $approved, $commentdata ) {
1134
- if ( 1 == crb_get_settings( 'spamcomm' ) && ! cerber_is_comment_allowed() ) {
1135
- $approved = 'spam';
1136
- }
1137
-
1138
- return $approved;
1139
- }, 10, 2 );
1140
-
1141
- /**
1142
- * If a comment must be denied
1143
- *
1144
- */
1145
- add_action( 'pre_comment_on_post', function ( $comment_post_ID ) {
1146
- global $cerber_status;
1147
-
1148
- $deny = false;
1149
-
1150
- if ( 1 != crb_get_settings( 'spamcomm' ) && ! cerber_is_comment_allowed() ) {
1151
- $deny = true;
1152
- }
1153
- elseif ( ! cerber_geo_allowed( 'geo_comment' ) ) {
1154
- $cerber_status = 16;
1155
- cerber_log(19);
1156
- $deny = true;
1157
- }
1158
-
1159
- if ( $deny ) {
1160
- setcookie( 'cerber-post-id', $comment_post_ID, time() + 60, '/' );
1161
- $comments = get_comments( array( 'number' => '1', 'post_id' => $comment_post_ID ) );
1162
- if ( $comments ) {
1163
- $loc = get_comment_link( $comments[0]->comment_ID );
1164
- } else {
1165
- $loc = get_permalink( $comment_post_ID ) . '#cerber-recaptcha-msg';
1166
- }
1167
- wp_safe_redirect( $loc );
1168
- exit;
1169
- }
1170
-
1171
- } );
1172
-
1173
- /**
1174
- * If submit comments via REST API is not allowed
1175
- *
1176
- */
1177
- add_filter( 'rest_allow_anonymous_comments', function ( $allowed, $request ) {
1178
- global $wp_cerber, $cerber_status;
1179
-
1180
- if ( ! cerber_is_allowed() ) {
1181
- $allowed = false;
1182
- }
1183
- if ( ! cerber_geo_allowed( 'geo_comment' ) ) {
1184
- ceber_log(19);
1185
- $cerber_status = 16;
1186
- $allowed = false;
1187
- }
1188
- elseif ( lab_is_blocked( $wp_cerber->getRemoteIp() ) ) {
1189
- $allowed = false;
1190
- }
1191
-
1192
- return $allowed;
1193
- }, 10, 2 );
1194
-
1195
- /**
1196
- * Check if a submitted comment is allowed
1197
- *
1198
- * @return bool
1199
- */
1200
- function cerber_is_comment_allowed(){
1201
- global $wp_cerber;
1202
-
1203
- if (is_admin()) return true;
1204
-
1205
- $deny = null;
1206
-
1207
- if ( ! cerber_is_allowed() ) {
1208
- $deny = 19;
1209
- }
1210
- elseif ( cerber_is_bot('botscomm') ) {
1211
- $remain = cerber_get_remain_count( null , true, 16, 3, 60);
1212
- if ($remain < 1) cerber_block_add( null, 6, '', 60 );
1213
- $deny = 16;
1214
- }
1215
- elseif ( ! $wp_cerber->reCaptchaValidate( 'comment' , true ) ) {
1216
- $deny = 16;
1217
- }
1218
- elseif ( lab_is_blocked( $wp_cerber->getRemoteIp() ) ) {
1219
- $deny = 19;
1220
- }
1221
-
1222
- if ( $deny ) {
1223
- cerber_log( $deny );
1224
- $ret = false;
1225
- }
1226
- else {
1227
- $ret = true;
1228
- }
1229
-
1230
- return $ret;
1231
- }
1232
-
1233
- /**
1234
- * Showing reCAPTCHA widget.
1235
- * Displaying error message on the comment form for a human.
1236
- *
1237
- */
1238
- add_filter( 'comment_form_submit_field', function ( $value ) {
1239
- global $wp_cerber, $post;
1240
-
1241
- if ( ! empty( $_COOKIE["cerber-post-id"] ) && absint( $_COOKIE["cerber-post-id"] ) == $post->ID ) {
1242
- //echo '<div id="cerber-recaptcha-msg">' . __( 'ERROR:', 'wp-cerber' ) . ' ' . $wp_cerber->reCaptchaMsg( 'comment' ) . '</div>';
1243
- echo '<div id="cerber-recaptcha-msg">' . __( 'ERROR:', 'wp-cerber' ) . ' ' . __('Sorry, human verification failed.') . '</div>';
1244
- echo '<script type="text/javascript">document.cookie = "cerber-post-id=0;path=/";</script>';
1245
- }
1246
-
1247
- $au = $wp_cerber->getSettings( 'recapcomauth' );
1248
- if ( ! $au || ( $au && ! is_user_logged_in() ) ) {
1249
- $wp_cerber->reCaptcha( 'widget', 'recapcom' );
1250
- }
1251
-
1252
- return $value;
1253
- } );
1254
-
1255
-
1256
- // Messages ----------------------------------------------------------------------
1257
-
1258
- /**
1259
- * Replace ANY system messages or add notify message above login form if IP is not allowed (blocked or locked out)
1260
- */
1261
- add_filter( 'login_errors', 'cerber_login_form_msg' ); // hook on POST if credentials was wrong
1262
- function cerber_login_form_msg( $errors ) {
1263
- global $error, $wp_cerber;
1264
- if ( cerber_can_msg() ) {
1265
- if ( ! cerber_is_allowed() ) {
1266
- $errors = $wp_cerber->getErrorMsg();
1267
- }
1268
- elseif ( ! $error && ( $msg = $wp_cerber->getRemainMsg() ) ) {
1269
- $errors .= '<p>' . $msg;
1270
- }
1271
- }
1272
-
1273
- return $errors;
1274
- }
1275
-
1276
- add_filter( 'shake_error_codes', 'cerber_login_failure_shake' ); // Shake it, baby!
1277
- function cerber_login_failure_shake( $shake_error_codes ) {
1278
- $shake_error_codes[] = 'cerber_wp_error';
1279
-
1280
- return $shake_error_codes;
1281
- }
1282
-
1283
- /*
1284
- Replace default login/logout URL with Custom login page URL
1285
- */
1286
- add_filter( 'site_url', 'cerber_login_logout', 9999, 4 );
1287
- add_filter( 'network_site_url', 'cerber_login_logout', 9999, 3 );
1288
- function cerber_login_logout( $url, $path, $scheme, $blog_id = 0 ) { // $blog_id only for 'site_url'
1289
- global $wp_cerber;
1290
- if ( $login_path = $wp_cerber->getSettings( 'loginpath' ) ) {
1291
- $url = str_replace( WP_LOGIN_SCRIPT, $login_path . '/', $url );
1292
- }
1293
-
1294
- return $url;
1295
- }
1296
-
1297
- /*
1298
- Replace default logout redirect URL with Custom login page URL
1299
- */
1300
- add_filter( 'wp_redirect', 'cerber_redirect', 9999, 2 );
1301
- function cerber_redirect( $location, $status ) {
1302
- global $wp_cerber;
1303
- if ( ($path = $wp_cerber->getSettings( 'loginpath' )) && ( 0 === strpos( $location, WP_LOGIN_SCRIPT . '?' ) ) ) {
1304
- $loc = explode( '?', $location );
1305
- $location = get_home_url() . '/' . $path . '/?' . $loc[1];
1306
- }
1307
-
1308
- return $location;
1309
- }
1310
-
1311
- // Access control ========================================================================================
1312
-
1313
- //add_action( 'init', 'cerber_access_control', 1 );
1314
- add_action( 'init', function () {
1315
- if ( crb_get_settings( 'adminphp' ) && ! is_user_logged_in() ) {
1316
- define( 'CONCATENATE_SCRIPTS', false );
1317
- }
1318
- cerber_access_control();
1319
- cerber_post_control();
1320
- }, 1 );
1321
-
1322
- /**
1323
- * Restrict access to vital parts of WP
1324
- *
1325
- */
1326
- function cerber_access_control() {
1327
- global $wp_cerber, $cerber_status;
1328
-
1329
- if ( is_admin() ) {
1330
- return;
1331
- }
1332
-
1333
- // IPs from the White List are allowed
1334
- $acl = cerber_acl_check();
1335
- if ( $acl == 'W' ) {
1336
- return;
1337
- }
1338
-
1339
- //if ( $acl == 'B' || cerber_block_check() ) {
1340
- if ( $acl == 'B' || !cerber_is_allowed() ) { // @since 5.8.2
1341
- $deny = true;
1342
- }
1343
- else {
1344
- $deny = false;
1345
- }
1346
-
1347
- $opt = $wp_cerber->getSettings();
1348
-
1349
- $script = cerber_last_uri();
1350
- if ( substr( $script, - 4 ) != '.php' ) {
1351
- $script .= '.php'; // Apache MultiViews enabled?
1352
- }
1353
-
1354
- if ( $script ) {
1355
- if ( $script == WP_LOGIN_SCRIPT || $script == WP_SIGNUP_SCRIPT || ( $script == WP_REG_URI && ! get_option( 'users_can_register' ) ) ) { // no direct access
1356
- if ( !empty( $opt['wplogin'] ) ) {
1357
- cerber_log( 50 );
1358
- cerber_soft_block_add( $wp_cerber->getRemoteIp(), 2, $script );
1359
- cerber_404_page();
1360
- }
1361
- if ( $deny || !empty( $opt['loginnowp'] ) ) {
1362
- cerber_log( 50 );
1363
- cerber_404_page();
1364
- }
1365
- }
1366
- elseif ( $script == WP_XMLRPC_SCRIPT || $script == WP_TRACKBACK_SCRIPT ) { // no direct access
1367
- if ( $deny || ! empty( $opt['xmlrpc'] ) ) {
1368
- cerber_log( 50 ); // @since 5.21
1369
- cerber_404_page();
1370
- }
1371
- elseif ( !cerber_geo_allowed( 'geo_xmlrpc' ) ) {
1372
- $cerber_status = 16;
1373
- cerber_log( 71 );
1374
- cerber_404_page();
1375
- }
1376
- }
1377
- }
1378
-
1379
- // TODO: the code below should be located before $script or be called in the beginning of cerber_404_page()
1380
-
1381
- // REST API
1382
- if ( $deny ) {
1383
- cerber_block_rest();
1384
- }
1385
- elseif ( cerber_is_rest_url() ) {
1386
- $rest_allowed = true;
1387
- if ( ! empty( $opt['norest'] ) ) {
1388
- $rest_allowed = false;
1389
- if ( $wp_cerber->getSettings( 'restauth' ) && is_user_logged_in() ) {
1390
- $rest_allowed = true;
1391
- }
1392
- elseif ( cerber_is_route_allowed() ) {
1393
- $rest_allowed = true;
1394
- }
1395
- }
1396
- /*
1397
- $rest_allowed = true;
1398
- if ( ! empty( $opt['norest'] ) && ! cerber_is_route_allowed() ) {
1399
- $rest_allowed = false;
1400
- }*/
1401
- if ( $rest_allowed && cerber_is_route_blocked() ) {
1402
- $rest_allowed = false;
1403
- }
1404
- if ( $rest_allowed && ! cerber_geo_allowed( 'geo_restapi' ) ) {
1405
- $rest_allowed = false;
1406
- $cerber_status = 16;
1407
- }
1408
- if ( ! $rest_allowed ) {
1409
- cerber_block_rest();
1410
- }
1411
- }
1412
-
1413
- // Some XML-RPC stuff
1414
- if ( $deny || ! empty( $opt['xmlrpc'] ) ) {
1415
- add_filter( 'xmlrpc_enabled', '__return_false' );
1416
- add_filter( 'pings_open', '__return_false' );
1417
- add_filter( 'bloginfo_url', 'cerber_pingback_url', 10, 2 );
1418
- remove_action( 'wp_head', 'rsd_link', 10 );
1419
- remove_action( 'wp_head', 'wlwmanifest_link', 10 );
1420
- }
1421
-
1422
- // Feeds
1423
- if ( $deny || ! empty( $opt['nofeeds'] ) ) {
1424
- remove_action( 'wp_head', 'feed_links', 2 );
1425
- remove_action( 'wp_head', 'feed_links_extra', 3 );
1426
-
1427
- remove_action( 'do_feed_rdf', 'do_feed_rdf', 10 );
1428
- remove_action( 'do_feed_rss', 'do_feed_rss', 10 );
1429
- remove_action( 'do_feed_rss2', 'do_feed_rss2', 10 );
1430
- remove_action( 'do_feed_atom', 'do_feed_atom', 10 );
1431
- remove_action( 'do_pings', 'do_all_pings', 10 );
1432
-
1433
- add_action( 'do_feed_rdf', 'cerber_404_page', 1 );
1434
- add_action( 'do_feed_rss', 'cerber_404_page', 1 );
1435
- add_action( 'do_feed_rss2', 'cerber_404_page', 1 );
1436
- add_action( 'do_feed_atom', 'cerber_404_page', 1 );
1437
- add_action( 'do_feed_rss2_comments', 'cerber_404_page', 1 );
1438
- add_action( 'do_feed_atom_comments', 'cerber_404_page', 1 );
1439
- }
1440
- }
1441
-
1442
- /**
1443
- * Antispam & Antibot for forms
1444
- *
1445
- */
1446
- //add_action( 'init', 'cerber_post_control', 2 );
1447
- function cerber_post_control(){
1448
- global $cerber_status;
1449
-
1450
- if ( !cerber_is_http_post() || cerber_acl_check( null, 'W' ) ) {
1451
- return;
1452
- }
1453
-
1454
- if ( !cerber_antibot_enabled('botsany') || !cerber_geo_rules('geo_submit')) {
1455
- return;
1456
- }
1457
-
1458
- // Exceptions -----------------------------------------------------------------------
1459
-
1460
- if ( cerber_is_post_exception() ) {
1461
- return;
1462
- }
1463
-
1464
- // Let's make the checks
1465
-
1466
- $deny = false;
1467
-
1468
- if ( ! cerber_is_allowed() ) {
1469
- $deny = true;
1470
- cerber_log(18);
1471
- }
1472
- elseif ( cerber_is_bot( 'botsany' ) ) {
1473
- $deny = true;
1474
- cerber_log( 17 );
1475
- }
1476
- elseif ( !cerber_geo_allowed( 'geo_submit' ) ) {
1477
- $deny = true;
1478
- $cerber_status = 16; // TODO: refactor cerber_log, include this status as a second parameter
1479
- cerber_log( 18 );
1480
- }
1481
- elseif ( lab_is_blocked( null, true ) ) {
1482
- $deny = true;
1483
- $cerber_status = 18;
1484
- cerber_log( 18 );
1485
- }
1486
-
1487
- if ($deny){
1488
- cerber_forbidden_page();
1489
- }
1490
-
1491
- }
1492
-
1493
- /**
1494
- * Exception for POST query control
1495
- *
1496
- * @return bool
1497
- */
1498
- function cerber_is_post_exception(){
1499
-
1500
- if ( defined( 'DOING_CRON' ) && DOING_CRON ) {
1501
- return true;
1502
- }
1503
-
1504
- // Admin || AJAX requests by unauthorized users
1505
- if ( is_admin() ) {
1506
- if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
1507
- if (is_user_logged_in()) {
1508
- return true;
1509
- }
1510
- }
1511
- else {
1512
- return true;
1513
- }
1514
- }
1515
-
1516
- // Comments
1517
- if ( 0 === strpos( trim( $_SERVER['REQUEST_URI'], '/' ), 'wp-comments-post.php' ) ) {
1518
- return true;
1519
- }
1520
-
1521
- // XML-RPC
1522
- if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
1523
- return true;
1524
- }
1525
-
1526
- // Trackback
1527
- if ( is_trackback() ) {
1528
- return true;
1529
- }
1530
-
1531
- // Login page
1532
- if ( cerber_is_login_request() ) {
1533
- return true;
1534
- }
1535
-
1536
- // REST API but not Contact Form 7 submission
1537
- if ( cerber_is_rest_url() ) {
1538
- if ( false === strpos( $_SERVER['REQUEST_URI'], 'contact-form-7' ) ) {
1539
- return true;
1540
- }
1541
- }
1542
-
1543
- return false;
1544
- }
1545
-
1546
- /*
1547
- * Disable pingback URL (hide from HEAD)
1548
- */
1549
- function cerber_pingback_url( $output, $show ) {
1550
- if ( $show == 'pingback_url' ) {
1551
- $output = '';
1552
- }
1553
-
1554
- return $output;
1555
- }
1556
-
1557
- /**
1558
- * Disable REST API
1559
- *
1560
- */
1561
- function cerber_block_rest() {
1562
- global $wp_version;
1563
- // OLD WP
1564
- add_filter( 'json_enabled', '__return_false' );
1565
- add_filter( 'json_jsonp_enabled', '__return_false' );
1566
- // WP 4.4, deprecated since 4.7
1567
- if ( version_compare( $wp_version, '4.7', '<' ) ) {
1568
- add_filter( 'rest_enabled', '__return_false', 9999 );
1569
- }
1570
- // WP 4.7
1571
- add_filter( 'rest_jsonp_enabled', '__return_false' );
1572
- // Links
1573
- remove_action( 'wp_head', 'rest_output_link_wp_head', 10 );
1574
- remove_action( 'template_redirect', 'rest_output_link_header', 11 );
1575
- // Default REST API hooks from default-filters.php
1576
- remove_action( 'init', 'rest_api_init' );
1577
- remove_action( 'rest_api_init', 'rest_api_default_filters', 10 );
1578
- remove_action( 'rest_api_init', 'register_initial_settings', 10 );
1579
- remove_action( 'rest_api_init', 'create_initial_rest_routes', 99 );
1580
- remove_action( 'parse_request', 'rest_api_loaded' );
1581
-
1582
- if ( cerber_is_rest_url() ) {
1583
- cerber_log( 70 );
1584
- //cerber_404_page();
1585
- cerber_forbidden_page(); // @since 6.0
1586
- }
1587
- }
1588
-
1589
- /*
1590
- * Redirection control: standard admin/login redirections
1591
- *
1592
- */
1593
- add_filter( 'wp_redirect', 'cerber_no_redirect', 10, 2 );
1594
- function cerber_no_redirect( $location, $status ) {
1595
- global $current_user, $wp_cerber;
1596
- if ( (!$current_user || $current_user->ID == 0) && $wp_cerber->getSettings( 'noredirect' ) ) {
1597
- $str = urlencode( '/wp-admin/' );
1598
- $rdr = explode('redirect_to=',$location);
1599
- if ( isset($rdr[1]) && strpos( $rdr[1], $str ) ) {
1600
- cerber_404_page();
1601
- }
1602
- }
1603
-
1604
- return $location;
1605
- }
1606
- /*
1607
- * Redirection control: no default aliases for redirections
1608
- *
1609
- */
1610
- if ( $wp_cerber->getSettings( 'noredirect' ) ) {
1611
- remove_action( 'template_redirect', 'wp_redirect_admin_locations', 1000 );
1612
- }
1613
- /*
1614
- * Stop user enumeration
1615
- *
1616
- */
1617
- add_action( 'template_redirect', 'cerber_canonical', 1 );
1618
- function cerber_canonical() {
1619
- if ( crb_get_settings( 'stopenum' ) ) {
1620
- if ( ! is_admin() && ! empty( $_GET['author'] ) ) {
1621
- cerber_404_page();
1622
- }
1623
- }
1624
- }
1625
- /*
1626
- if ( $wp_cerber->getSettings( 'hashauthor' ) ) {
1627
- add_filter( 'request',
1628
- function ( $vars ) {
1629
- if (isset($vars['author_name']) && !is_admin()) {
1630
- $vars['author_name'] = '><';
1631
- }
1632
-
1633
- return $vars;
1634
- } );
1635
- }
1636
- */
1637
-
1638
- /*
1639
- Can login form message be shown?
1640
- */
1641
- function cerber_can_msg() {
1642
- if ( ! isset( $_REQUEST['action'] ) ) {
1643
- return true;
1644
- }
1645
- if ( $_REQUEST['action'] == 'login' ) {
1646
- return true;
1647
- }
1648
-
1649
- return false;
1650
- //if ( !in_array( $action, array( 'postpass', 'logout', 'lostpassword', 'retrievepassword', 'resetpass', 'rp', 'register', 'login' );
1651
- }
1652
-
1653
-
1654
- // Cookies ---------------------------------------------------------------------------------
1655
- /*
1656
- Mark user with Cerber Groove
1657
- @since 1.3
1658
- */
1659
- add_action( 'auth_cookie_valid', 'cerber_cookie1', 10, 2 );
1660
- function cerber_cookie1( $cookie_elements = null, $user = null ) {
1661
- global $current_user;
1662
- if ( ! $user ) {
1663
- $user = wp_get_current_user();
1664
- }
1665
- $expire = time() + apply_filters( 'auth_cookie_expiration', 14 * 24 * 3600, $user->ID, true ) + ( 24 * 3600 );
1666
- cerber_set_groove( $expire );
1667
- }
1668
-
1669
- /*
1670
- Mark switched user with Cerber Groove
1671
- @since 1.6
1672
- */
1673
- add_action( 'set_logged_in_cookie', 'cerber_cookie2', 10, 5 );
1674
- function cerber_cookie2( $logged_in_cookie, $expire, $expiration, $user_id, $logged_in ) {
1675
- cerber_set_groove( $expire );
1676
- }
1677
-
1678
- /*
1679
- Track BAD cookies with non-existence user or bad password (hash)
1680
- */
1681
- add_action( 'auth_cookie_bad_username', 'cerber_cookie_bad' );
1682
- add_action( 'auth_cookie_bad_hash', 'cerber_cookie_bad' );
1683
- function cerber_cookie_bad( $cookie_elements ) {
1684
- cerber_login_failed( $cookie_elements['username'] );
1685
- }
1686
-
1687
- /**
1688
- * Is bot detection engine enabled in a given rule_id
1689
- *
1690
- * @param $location string|array ID of the location
1691
- *
1692
- * @return bool true if enabled
1693
- */
1694
- function cerber_antibot_enabled($location) {
1695
- global $wp_cerber;
1696
-
1697
- if ($wp_cerber->getSettings( 'botsnoauth' ) && is_user_logged_in()){
1698
- return false;
1699
- }
1700
-
1701
- if ( is_array( $location ) ) {
1702
- foreach ( $location as $loc ) {
1703
- if ( $wp_cerber->getSettings( $loc ) ) {
1704
- return true;
1705
- }
1706
- }
1707
- }
1708
- else {
1709
- if ( $wp_cerber->getSettings( $location ) ) {
1710
- return true;
1711
- }
1712
- }
1713
-
1714
- return false;
1715
- }
1716
-
1717
- /**
1718
- * Print out the antibot/antispam jQuery code
1719
- *
1720
- * @param $location string|array Location (setting)
1721
- */
1722
- function cerber_antibot_code($location) {
1723
- if ( ! cerber_antibot_enabled( $location ) ) {
1724
- return;
1725
- }
1726
-
1727
- $values = cerber_antibot_gene();
1728
-
1729
- if ( empty( $values ) || !is_array( $values ) ) {
1730
- return;
1731
- }
1732
-
1733
- ?>
1734
- <script type="text/javascript">
1735
- jQuery(document).ready(function ($) {
1736
- //$( document ).ajaxStart(function() {
1737
- //});
1738
-
1739
- <?php // Append form fields directly to the all forms ?>
1740
-
1741
- for (var i = 0; i < document.forms.length; ++i) {
1742
- var form = document.forms[i];
1743
- <?php
1744
- foreach ( $values[0] as $value ) {
1745
- echo 'if ($(form).attr("method") != "get") { $(form).append(\'<input type="hidden" name="' . $value[0] . '" value="' . $value[1] . '" />\'); }'."\n";
1746
- }
1747
- ?>
1748
- }
1749
-
1750
- <?php // Ordinary submit ?>
1751
-
1752
- $(document).on('submit', 'form', function () {
1753
- <?php
1754
- foreach ( $values[0] as $value ) {
1755
- echo 'if ($(this).attr("method") != "get") { $(this).append(\'<input type="hidden" name="' . $value[0] . '" value="' . $value[1] . '" />\'); }'."\n";
1756
- }
1757
- ?>
1758
- return true;
1759
- });
1760
-
1761
- <?php // Pure AJAX submit with two different types of form data (object and string) ?>
1762
-
1763
- jQuery.ajaxSetup({
1764
- beforeSend: function (e, data) {
1765
-
1766
- //console.log(Object.getOwnPropertyNames(data).sort());
1767
- //console.log(data.type);
1768
-
1769
- if (data.type !== 'POST') return;
1770
-
1771
- if (typeof data.data === 'object' && data.data !== null) {
1772
- <?php
1773
- foreach ( $values[0] as $value ) {
1774
- echo 'data.data.append("' . $value[0] . '", "' . $value[1] . '");'."\n";
1775
- }
1776
- ?>
1777
- }
1778
- else {
1779
- data.data = data.data + '<?php
1780
- foreach ( $values[0] as $value ) {
1781
- echo '&' . $value[0] . '=' . $value[1];
1782
- }
1783
- ?>';
1784
- }
1785
- }
1786
- });
1787
-
1788
- });
1789
- </script>
1790
- <?php
1791
-
1792
- }
1793
-
1794
- /**
1795
- * Generates and saves antibot markers
1796
- *
1797
- * @return array|bool
1798
- */
1799
- function cerber_antibot_gene($recreate = false) {
1800
-
1801
- if ( !crb_get_settings('botsany') && !crb_get_settings('botscomm') && !crb_get_settings('botsreg') ) {
1802
- return false;
1803
- }
1804
-
1805
- $ret = array();
1806
-
1807
- if (!$recreate) {
1808
- $ret = cerber_get_site_option( 'cerber-antibot' );
1809
- }
1810
-
1811
- if ( $recreate || !$ret ) {
1812
-
1813
- $ret = array();
1814
-
1815
- $max = rand( 2, 4 );
1816
- for ( $i = 1; $i <= $max; $i ++ ) {
1817
- $length = rand( 6, 16 );
1818
- $string1 = str_shuffle( 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-' );
1819
- $string2 = str_shuffle( '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.@*_[]' );
1820
- $ret[0][] = array( substr( $string1, 0, $length ), substr( $string2, 0, $length ) );
1821
- }
1822
-
1823
- $max = rand( 2, 4 );
1824
- for ( $i = 1; $i <= $max; $i ++ ) {
1825
- $length = rand( 6, 16 );
1826
- $string1 = str_shuffle( 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-' );
1827
- $string2 = str_shuffle( '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.@*_[]' );
1828
- $ret[1][] = array( substr( $string1, 0, $length ), substr( $string2, 0, $length ) );
1829
- }
1830
-
1831
- update_site_option( 'cerber-antibot', $ret );
1832
- }
1833
-
1834
- return $ret;
1835
- }
1836
-
1837
- /**
1838
- * Is a POST request (a form) submitted by a bot?
1839
- *
1840
- * @param $location string identificator of a place where we are check for a bot
1841
- *
1842
- * @return bool
1843
- */
1844
- function cerber_is_bot($location = '') {
1845
- global $wp_cerber, $cerber_status;
1846
- static $ret = null;
1847
-
1848
- if ( isset( $ret ) ) {
1849
- return $ret;
1850
- }
1851
-
1852
- if ( ! $location || ! cerber_is_http_post() || ( defined( 'DOING_CRON' ) && DOING_CRON ) ) {
1853
- $ret = false;
1854
-
1855
- return $ret;
1856
- }
1857
-
1858
- // Admin || AJAX requests by unauthorized users
1859
- if ( is_admin() ) {
1860
- if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
1861
- if ( is_user_logged_in() ) {
1862
- $ret = false;
1863
- }
1864
- elseif ( ! empty( $_POST['action'] ) ) {
1865
- if ($_POST['action'] == 'heartbeat'){ // WP heartbeat
1866
- $ret = false;
1867
- }
1868
- }
1869
- elseif ( crb_get_settings( 'botssafe' ) ) {
1870
- $ret = false;
1871
- }
1872
- }
1873
- else {
1874
- $ret = false;
1875
- }
1876
- }
1877
-
1878
- if ($ret !== null) {
1879
- return $ret;
1880
- }
1881
-
1882
- if ( ! cerber_antibot_enabled( $location ) ) {
1883
- $ret = false;
1884
-
1885
- return $ret;
1886
- }
1887
-
1888
- // Antibot whitelist
1889
- if ( ( $list = crb_get_settings( 'botswhite' ) ) && is_array( $list ) ) {
1890
- foreach ( $list as $exception ) {
1891
- if ( false !== strpos( trim( $_SERVER['REQUEST_URI'], '/' ), $exception ) ) {
1892
- $ret = false;
1893
- return $ret;
1894
- }
1895
- }
1896
- }
1897
-
1898
- $antibot = cerber_antibot_gene();
1899
-
1900
- $ret = false;
1901
-
1902
- if ( ! empty( $antibot ) ) {
1903
-
1904
- foreach ( $antibot[0] as $fields ) {
1905
- if ( empty( $_POST[ $fields[0] ] ) || $_POST[ $fields[0] ] != $fields[1] ) {
1906
- $ret = true;
1907
- break;
1908
- }
1909
- }
1910
-
1911
- if (!$ret){
1912
- foreach ( $antibot[1] as $fields ) {
1913
- if ( empty( $_COOKIE[ $fields[0] ] ) || $_COOKIE[ $fields[0] ] != $fields[1] ) {
1914
- $ret = true;
1915
- break;
1916
- }
1917
- }
1918
- }
1919
-
1920
- if ( $ret ) {
1921
- $cerber_status = 11;
1922
- lab_save_push( $wp_cerber->getRemoteIp(), 333, '' );
1923
- }
1924
- }
1925
-
1926
- return $ret;
1927
- }
1928
-
1929
- function cerber_geo_allowed( $rule_id = '' ) {
1930
- global $wp_cerber;
1931
-
1932
- if ( !$rule_id || ( defined( 'DOING_CRON' ) && DOING_CRON ) || !lab_lab() ) {
1933
- return true;
1934
- }
1935
-
1936
- $tag = cerber_acl_check();
1937
- if ( $tag == 'W' ) {
1938
- return true;
1939
- }
1940
-
1941
- $rule = cerber_geo_rules( $rule_id );
1942
- if ( $rule && $country = lab_get_country( $wp_cerber->getRemoteIp(), false ) ) {
1943
- if ( in_array( $country, $rule['list'] ) ) {
1944
- if ( $rule['type'] == 'W' ) {
1945
- return true;
1946
- }
1947
-
1948
- return false;
1949
- }
1950
- if ( $rule['type'] == 'W' ) {
1951
- return false;
1952
- }
1953
-
1954
- return true;
1955
- }
1956
-
1957
- return true;
1958
- }
1959
-
1960
- /**
1961
- * Retrieve and return GEO rule(s) from the DB
1962
- *
1963
- * @param string $rule_id Slug of a rule
1964
- *
1965
- * @return bool|array If a rule exists return array of countries
1966
- */
1967
- function cerber_geo_rules( $rule_id = '' ) {
1968
- global $wpdb;
1969
-
1970
- if (is_multisite()) {
1971
- $geo = $wpdb->get_var( 'SELECT meta_value FROM ' . $wpdb->sitemeta . ' WHERE meta_key = "geo_rule_set"' );
1972
- }
1973
- else {
1974
- $geo = $wpdb->get_var( 'SELECT option_value FROM ' . $wpdb->options . ' WHERE option_name = "geo_rule_set"' );
1975
- }
1976
-
1977
- if ( $geo ) {
1978
- $rules = unserialize( $geo );
1979
- if ( $rule_id ) {
1980
- if ( ! empty( $rules[ $rule_id ] ) ) {
1981
- $ret = $rules[ $rule_id ];
1982
- }
1983
- else {
1984
- $ret = false;
1985
- }
1986
- }
1987
- else {
1988
- $ret = $rules;
1989
- }
1990
- }
1991
- else {
1992
- $ret = false;
1993
- }
1994
-
1995
- return $ret;
1996
- }
1997
-
1998
- /**
1999
- * Set user session expiration
2000
- *
2001
- */
2002
- add_filter( 'auth_cookie_expiration', function ( $expire ) {
2003
- $time = crb_get_settings( 'auth_expire' );
2004
- if ( $time ) {
2005
- $expire = 60 * $time;
2006
- }
2007
-
2008
- return $expire;
2009
- } );
2010
-
2011
- // Track various activity -------------------------------------------------------------------------
2012
-
2013
- add_action( 'wp_login', function ( $login, $user ) {
2014
- global $wp_cerber_user_id;
2015
- if ( ! empty( $_POST['log'] ) ) { // default WP form
2016
- $user_login = htmlspecialchars( $_POST['log'] );
2017
- }
2018
- else {
2019
- $user_login = $login;
2020
- }
2021
- $wp_cerber_user_id = $user->ID;
2022
- cerber_log( 5, $user_login, $user->ID );
2023
- }, 10, 2 );
2024
-
2025
- /**
2026
- * Catching some cases of authentication without using login form or not a default user login process
2027
- */
2028
- add_action( 'set_auth_cookie', function () {
2029
- add_action( 'shutdown', function () { // deferred to allow the possible 'wp_login' action be logged first
2030
- if ($user_id = get_current_user_id()) {
2031
- cerber_log( 5, '', $user_id );
2032
- }
2033
- } );
2034
- } );
2035
-
2036
- /*add_action( 'wp_logout', function() {
2037
- global $user_ID;
2038
- if ( ! $user_ID ) {
2039
- $user = wp_get_current_user();
2040
- $user_ID = $user->ID;
2041
- }
2042
- cerber_log( 6, '', $user_ID );
2043
- });*/
2044
-
2045
- add_action( 'clear_auth_cookie', function () {
2046
- $uid = get_current_user_id();
2047
- if ( $uid ) {
2048
- cerber_log( 6, '', $uid );
2049
- }
2050
- } );
2051
-
2052
- //add_action( 'lostpassword_post', 'cerber_password_post' );
2053
- add_action( 'retrieve_password', function ( $user_login ) {
2054
- cerber_log( 21, $user_login );
2055
- } );
2056
-
2057
- add_action( 'password_reset', 'crb_pass_reset' );
2058
- add_action( 'crb_after_reset', 'crb_pass_reset', 10, 2);
2059
-
2060
- function crb_pass_reset( $user, $user_id = null) {
2061
- if ( ! $user && $user_id ) {
2062
- $user = get_user_by( 'id', $user_id );
2063
- }
2064
- if ( ! $user ) {
2065
- return;
2066
- }
2067
- cerber_log( 20, $user->user_login, $user->ID );
2068
- }
2069
-
2070
- //add_action( 'register_new_user', function ( $user_id ) { // OLD
2071
- // Fires in wp_insert_user()
2072
- add_action( 'user_register', function ( $user_id ) { // @since 5.6
2073
- $cid = get_current_user_id();
2074
- if ($user = get_user_by( 'ID', $user_id )) {
2075
- if ( $cid && $cid != $user_id ) {
2076
- $ac = 1;
2077
- }
2078
- else {
2079
- $ac = 2;
2080
- }
2081
- cerber_log( $ac, $user->user_login, $user_id );
2082
- crb_log_user_ip( $user_id, $cid );
2083
- }
2084
- });
2085
-
2086
- // Fires after a new user has been created in WP dashboard.
2087
- add_action( 'edit_user_created_user', function ( $user_id, $notify = null ) {
2088
- if ( $user_id && $user = get_user_by( 'ID', $user_id ) ) {
2089
- cerber_log( 1, $user->user_login, $user_id );
2090
- crb_log_user_ip( $user_id );
2091
- }
2092
- }, 10, 2 );
2093
-
2094
- // Log IP address of user registration independently
2095
- function crb_log_user_ip( $user_id, $by_user = null ) {
2096
- global $wp_cerber;
2097
- if ( ! $user_id ) {
2098
- return;
2099
- }
2100
- if ( ! $by_user ) {
2101
- $by_user = get_current_user_id();
2102
- }
2103
- add_user_meta( $user_id, '_crb_reg_', array( 'IP' => $wp_cerber->getRemoteIp(), 'user' => $by_user ) );
2104
- }
2105
-
2106
- // Lockouts routines ---------------------------------------------------------------------
2107
-
2108
- /**
2109
- * Lock out IP address if it is an alien IP only (browser does not have valid Cerber groove)
2110
- *
2111
- * @param $ip string IP address to block
2112
- * @param integer $reason_id ID of reason of blocking
2113
- * @param string $details Reason of blocking
2114
- * @param null $duration Duration of blocking
2115
- *
2116
- * @return bool|false|int
2117
- */
2118
- function cerber_soft_block_add( $ip, $reason_id, $details = '', $duration = null ) {
2119
- if ( cerber_check_groove() ) {
2120
- return false;
2121
- }
2122
-
2123
- return cerber_block_add( $ip, $reason_id, $details, $duration );
2124
- }
2125
-
2126
- /**
2127
- * Lock out IP address
2128
- *
2129
- * @param $ip string IP address to block
2130
- * @param integer $reason_id ID of reason of blocking
2131
- * @param string $details Reason of blocking
2132
- * @param int $duration Duration of blocking
2133
- * @param bool $check_acl deprecated @since 5.7 Check for ACL
2134
- *
2135
- * @return bool|false|int
2136
- */
2137
- function cerber_block_add( $ip = '', $reason_id = 1, $details = '', $duration = null, $check_acl = true ) {
2138
- global $wpdb, $wp_cerber;
2139
-
2140
- //$wp_cerber->setProcessed();
2141
-
2142
- if ( empty($ip) ) {
2143
- $ip = $wp_cerber->getRemoteIp();
2144
- }
2145
-
2146
- if ( cerber_get_block( $ip ) ) {
2147
- return false;
2148
- }
2149
-
2150
- if ( cerber_acl_check( $ip ) ) {
2151
- return false;
2152
- }
2153
-
2154
- $ip_address = $ip;
2155
-
2156
- lab_save_push( $ip, $reason_id, $details );
2157
-
2158
- if ( $wp_cerber->getSettings( 'subnet' ) ) {
2159
- $ip = cerber_get_subnet( $ip );
2160
- $activity = 11;
2161
- } else {
2162
- $activity = 10;
2163
- }
2164
-
2165
- if ( $wpdb->get_var( $wpdb->prepare( 'SELECT count(ip) FROM ' . CERBER_BLOCKS_TABLE . ' WHERE ip = %s', $ip ) ) ) {
2166
- return false;
2167
- }
2168
-
2169
- $reason = cerber_get_reason( $reason_id );
2170
- if ($details) $reason .= ': <b>' . $details . '</b>';
2171
-
2172
- if ( ! $duration ) {
2173
- $duration = cerber_calc_duration( $ip );
2174
- }
2175
- $until = time() + $duration;
2176
-
2177
- //$result = $wpdb->query($wpdb->prepare('INSERT INTO '. CERBER_BLOCKS_TABLE . ' (ip,block_until,reason) VALUES (%s,%d,%s)',$ip,$until,$reason));
2178
- $result = $wpdb->insert( CERBER_BLOCKS_TABLE, array(
2179
- 'ip' => $ip,
2180
- 'block_until' => $until,
2181
- 'reason' => $reason
2182
- ), array( '%s', '%d', '%s' ) );
2183
-
2184
- if ( $result ) {
2185
- cerber_log( $activity, null, null, $ip_address );
2186
- $wp_cerber->setLocked();
2187
- do_action( 'cerber_ip_locked', array( 'IP' => $ip_address, 'reason' => $reason ) );
2188
- $result = true;
2189
- }
2190
- else {
2191
- cerber_db_error_log();
2192
- $result = false;
2193
- }
2194
-
2195
- if ( $wp_cerber->getSettings( 'notify' ) ) {
2196
- //$count = $wpdb->get_var( 'SELECT count(ip) FROM ' . CERBER_BLOCKS_TABLE );
2197
- $count = cerber_blocked_num();
2198
- if ( $count > $wp_cerber->getSettings( 'above' ) ) {
2199
- cerber_send_notify( 'lockout', '', $ip_address );
2200
- }
2201
- }
2202
-
2203
- return $result;
2204
- }
2205
-
2206
- function cerber_block_delete( $ip ) {
2207
- global $wpdb;
2208
-
2209
- return $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . CERBER_BLOCKS_TABLE . ' WHERE ip = %s', $ip ) );
2210
- }
2211
-
2212
-
2213
- /**
2214
- *
2215
- * Check if an IP address is currently blocked. With C subnet also.
2216
- *
2217
- * @param string $ip an IP address
2218
- *
2219
- * @return bool true if IP is locked out
2220
- */
2221
- function cerber_block_check( $ip = '' ) {
2222
-
2223
- // @since 4.8
2224
- if (cerber_get_block($ip)) return true;
2225
-
2226
- return false;
2227
- }
2228
-
2229
- /**
2230
- *
2231
- * Return the lockout row for an IP if it is blocked. With C subnet also.
2232
- *
2233
- * @param string $ip an IP address
2234
- *
2235
- * @return object|bool object if IP is locked out, false otherwise
2236
- */
2237
- function cerber_get_block( $ip = '' ) {
2238
- global $wpdb, $wp_cerber;
2239
-
2240
- if ( ! $ip ) {
2241
- $wp_cerber = get_wp_cerber();
2242
- $ip = $wp_cerber->getRemoteIp();
2243
- }
2244
-
2245
- if ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
2246
- return false;
2247
- }
2248
-
2249
- $where = ' WHERE ip = "' . $ip . '"';
2250
- if ( cerber_is_ipv4( $ip ) ) {
2251
- $subnet = cerber_get_subnet( $ip );
2252
- $where .= ' OR ip = "' . $subnet . '"';
2253
- }
2254
- if ( $ret = $wpdb->get_row( 'SELECT * FROM ' . CERBER_BLOCKS_TABLE . $where ) ) {
2255
- return $ret;
2256
- }
2257
-
2258
- return false;
2259
- }
2260
-
2261
- // TODO: replace all entrance of $count = $wpdb->get_var('SELECT count(ip) FROM '. CERBER_BLOCKS_TABLE ); with this function
2262
- /**
2263
- * Return the number of currently locked out IPs
2264
- *
2265
- * @return int the number of currently locked out IPs
2266
- * @since 3.0
2267
- */
2268
- function cerber_blocked_num(){
2269
- global $wpdb;
2270
- $count = $wpdb->get_var('SELECT count(ip) FROM '. CERBER_BLOCKS_TABLE );
2271
- return absint($count);
2272
- }
2273
-
2274
- /*
2275
- Calculation duration of blocking (lockout) IP address based on settings & rules.
2276
- */
2277
- function cerber_calc_duration( $ip ) {
2278
- global $wpdb, $wp_cerber;
2279
- $range = time() - crb_get_settings( 'aglast' ) * 3600;
2280
- $lockouts = $wpdb->get_var( $wpdb->prepare( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE ip = %s AND activity IN (10,11) AND stamp > %d', $ip, $range ) );
2281
- if ( $lockouts >= crb_get_settings( 'aglocks' ) ) {
2282
- return crb_get_settings( 'agperiod' ) * 3600;
2283
- }
2284
-
2285
- return crb_get_settings( 'lockout' ) * 60;
2286
- }
2287
-
2288
- /**
2289
- * Calculation of remaining attempts
2290
- *
2291
- * @param $ip string an IP address
2292
- * @param $check_acl bool if true will check the White IP ACL first
2293
- * @param $activity string comma-separated list of activity IDs to calculate for
2294
- * @param $allowed int Allowed attempts within $period
2295
- * @param $period int Period for count attempts
2296
- *
2297
- * @return int Allowed attempts for now
2298
- */
2299
- function cerber_get_remain_count( $ip = '', $check_acl = true, $activity = '7,51,52', $allowed = null, $period = null ) {
2300
- global $wpdb, $wp_cerber;
2301
- if ( ! $ip ) {
2302
- $ip = $wp_cerber->getRemoteIp();
2303
- }
2304
-
2305
- if ( ! $allowed ) {
2306
- $allowed = absint( crb_get_settings( 'attempts' ) );
2307
- }
2308
-
2309
- if ( $check_acl && cerber_acl_check( $ip, 'W' ) ) {
2310
- return $allowed; // whitelist = infinity attempts
2311
- }
2312
-
2313
- if ( ! $period ) {
2314
- $period = absint( crb_get_settings( 'period' ) );
2315
- }
2316
-
2317
- $range = time() - $period * 60;
2318
- // TODO: remove prepare, replace $activity with an array of integer
2319
- $attempts = $wpdb->get_var( $wpdb->prepare( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE ip = %s AND activity IN (%s) AND stamp > %d', $ip, $activity, $range ) );
2320
-
2321
- if ( ! $attempts ) {
2322
- return $allowed;
2323
- }
2324
- else {
2325
- $ret = $allowed - $attempts;
2326
- }
2327
- $ret = $ret < 0 ? 0 : $ret;
2328
-
2329
- return $ret;
2330
- }
2331
-
2332
- /**
2333
- * Is a given IP is allowed to do restricted things?
2334
- * Here Cerber makes its decision.
2335
- *
2336
- * @param $ip string IP address
2337
- *
2338
- * @return bool
2339
- */
2340
- function cerber_is_allowed( $ip = '' ) {
2341
-
2342
- if ( ! $ip ) {
2343
- $wp_cerber = get_wp_cerber();
2344
- $ip = $wp_cerber->getRemoteIp();
2345
- }
2346
-
2347
- if ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
2348
- return false;
2349
- }
2350
-
2351
- // @since 4.7.9
2352
- if ( cerber_block_check( $ip ) ) {
2353
- return false;
2354
- }
2355
-
2356
- $tag = cerber_acl_check( $ip );
2357
- if ( $tag == 'W' ) {
2358
- return true;
2359
- }
2360
- if ( $tag == 'B' ) {
2361
- return false;
2362
- }
2363
-
2364
- /* @since 4.7.9
2365
- if ( cerber_block_check( $ip ) ) {
2366
- return false;
2367
- }*/
2368
-
2369
- if ( cerber_is_citadel() ) {
2370
- return false;
2371
- }
2372
-
2373
- if ( lab_is_blocked( $ip, false ) ) {
2374
- return false;
2375
- }
2376
-
2377
- return true;
2378
- }
2379
-
2380
- /**
2381
- * Check if a given username is not permitted to login or register
2382
- *
2383
- * @param $username string
2384
- *
2385
- * @return bool true if username is prohibited
2386
- */
2387
- function cerber_is_prohibited( $username ) {
2388
- if ( $list = (array) crb_get_settings( 'prohibited' ) ) {
2389
- foreach ( $list as $item ) {
2390
- if ( mb_substr( $item, 0, 1 ) == '/' && mb_substr( $item, - 1 ) == '/' ) {
2391
- $pattern = trim( $item, '/' );
2392
- if ( mb_ereg_match( $pattern, $username, 'i' ) ) {
2393
- return true;
2394
- }
2395
- }
2396
- elseif ($username === $item){
2397
- return true;
2398
- }
2399
- }
2400
- }
2401
-
2402
- return false;
2403
- }
2404
-
2405
- // TODO: Merge with $wp_cerber->getStatus();
2406
- function cerber_get_status( $ip ) {
2407
- global $cerber_status;
2408
-
2409
- if ( ! empty( $cerber_status ) ) {
2410
- return absint($cerber_status);
2411
- }
2412
-
2413
- if ( cerber_block_check( $ip ) ) {
2414
- return 13;
2415
- }
2416
-
2417
- $tag = cerber_acl_check( $ip );
2418
- if ( $tag == 'W' ) {
2419
- return 0;
2420
- }
2421
- if ( $tag == 'B' ) {
2422
- return 14;
2423
- }
2424
-
2425
- if ( cerber_is_citadel() ) {
2426
- return 12;
2427
- }
2428
-
2429
- if ( lab_is_blocked( $ip, false ) ) {
2430
- return 15;
2431
- }
2432
-
2433
-
2434
- return 0;
2435
- }
2436
-
2437
- // Access lists (ACL) routines --------------------------------------------------------------------------------
2438
-
2439
- // TODO: move to dashboard.php
2440
- /**
2441
- * Add IP to specified access list
2442
- *
2443
- * @param $ip string|array single IP address, string with IP network, range or associative range array
2444
- * @param $tag string 'B'|'W'
2445
- *
2446
- * @return bool|int|object Result of operation
2447
- */
2448
- function cerber_acl_add( $ip, $tag, $comment = '') {
2449
- global $wpdb;
2450
- if ( is_string( $ip ) ) {
2451
- if ( ! cerber_is_ipv4( $ip ) ) {
2452
- $ip = cerber_short_ipv6( $ip );
2453
- }
2454
- if ( $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(ip) FROM ' . CERBER_ACL_TABLE . ' WHERE ip = %s', $ip ) ) ) {
2455
- return false; //__( 'Element is already in list', 'wp-cerber' );
2456
- }
2457
- $range = cerber_any2range( $ip );
2458
- if ( is_array( $range ) ) {
2459
- $begin = $range['begin'];
2460
- $end = $range['end'];
2461
- }
2462
- else {
2463
- if (cerber_is_ipv4($ip)) {
2464
- $begin = ip2long( $ip );
2465
- $end = ip2long( $ip );
2466
- }
2467
- else{
2468
- $begin = 0;
2469
- $end = 0;
2470
- }
2471
- }
2472
-
2473
- $result = $wpdb->insert( CERBER_ACL_TABLE, array( 'ip' => $ip,
2474
- 'ip_long_begin' => $begin,
2475
- 'ip_long_end' => $end,
2476
- 'tag' => $tag,
2477
- 'comments' => $comment
2478
- ), array( '%s', '%d', '%d', '%s', '%s' ) );
2479
- return $result;
2480
- }
2481
- elseif ( is_array( $ip ) ) {
2482
- $range = $ip['range'];
2483
- $begin = $ip['begin'];
2484
- $end = $ip['end'];
2485
- if ( $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(ip) FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin = %d AND ip_long_end = %d', $begin, $end ) ) ) {
2486
- return false;
2487
- }
2488
-
2489
- $result = $wpdb->insert( CERBER_ACL_TABLE, array( 'ip' => $range,
2490
- 'ip_long_begin' => $begin,
2491
- 'ip_long_end' => $end,
2492
- 'tag' => $tag,
2493
- 'comments' => $comment
2494
- ), array( '%s', '%d', '%d', '%s', '%s' ) );
2495
-
2496
- return $result;
2497
-
2498
- //return $wpdb->query( $wpdb->prepare( 'INSERT INTO ' . CERBER_ACL_TABLE . ' (ip, ip_long_begin, ip_long_end, tag) VALUES (%s,%d,%d,%s)', $range, $begin, $end, $tag ) );
2499
- }
2500
-
2501
- return false;
2502
- }
2503
- // TODO: move to dashboard.php
2504
- function cerber_add_white( $ip, $comment = '' ) {
2505
- return cerber_acl_add( $ip, 'W', $comment );
2506
- }
2507
- // TODO: move to dashboard.php
2508
- function cerber_add_black( $ip, $comment = '') {
2509
- return cerber_acl_add( $ip, 'B', $comment );
2510
- }
2511
- // TODO: move to dashboard.php
2512
- function cerber_acl_remove( $ip ) {
2513
- global $wpdb;
2514
- if ( is_string( $ip ) ) {
2515
- return $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . CERBER_ACL_TABLE . ' WHERE ip = %s ', $ip ) );
2516
- } elseif ( is_array( $ip ) ) {
2517
- return $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin = %d AND ip_long_end = %d', $ip['begin'], $ip['end'] ) );
2518
- }
2519
-
2520
- return false;
2521
- }
2522
-
2523
- // TODO: move to dashboard.php
2524
- /**
2525
- * Can a given IP (user input) be added to the blacklist
2526
- *
2527
- * @param $ip
2528
- * @param string $list
2529
- *
2530
- * @return bool
2531
- */
2532
- function cerber_can_be_listed( $ip, $list = 'B' ) {
2533
- global $wp_cerber;
2534
- if ( $list == 'B' ) {
2535
- if ( crb_acl_is_white( $wp_cerber->getRemoteIp() ) ) {
2536
- return true;
2537
- }
2538
- if ( filter_var( $ip, FILTER_VALIDATE_IP ) ) {
2539
- if ( cerber_is_myip( $ip ) ) {
2540
- return false;
2541
- }
2542
- }
2543
- $range = cerber_any2range( $ip );
2544
- if ( cerber_is_ip_in_range( $range ) ) {
2545
- return false;
2546
- }
2547
-
2548
- return true;
2549
- }
2550
-
2551
- return true;
2552
- }
2553
-
2554
- /**
2555
- * Check ACLs for given IP. Some extra lines for performance reason.
2556
- *
2557
- * @param string $ip
2558
- * @param string $tag
2559
- *
2560
- * @return bool|string
2561
- */
2562
- function cerber_acl_check( $ip = null, $tag = '' ) {
2563
- global $wpdb, $wp_cerber;
2564
- static $cache; // @since 5.26
2565
-
2566
- if ( ! $ip ) {
2567
- $wp_cerber = get_wp_cerber();
2568
- $ip = $wp_cerber->getRemoteIp();
2569
- //$ip = cerber_get_remote_ip();
2570
- }
2571
-
2572
- $key = cerber_get_id_ip( $ip ) . $tag;
2573
-
2574
- if ( isset( $cache[ $key ] ) ) {
2575
- return $cache[ $key ];
2576
- }
2577
-
2578
- if ( ! cerber_is_ipv4( $ip ) ) {
2579
- $ret = cerber_acl_checkV6( $ip, $tag );
2580
- $cache[ $key ] = $ret;
2581
- return $ret;
2582
- }
2583
-
2584
- $long = ip2long( $ip );
2585
-
2586
- if ( $tag ) {
2587
- if ( $tag != 'W' && $tag != 'B' ) {
2588
- $ret = false;
2589
- }
2590
- elseif ( $wpdb->get_var( 'SELECT ip FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin <= '.$long.' AND '.$long.' <= ip_long_end AND tag = "'.$tag.'" LIMIT 1' ) ) {
2591
- $ret = true;
2592
- }
2593
- else {
2594
- $ret = false;
2595
- }
2596
-
2597
- $cache[ $key ] = $ret;
2598
- return $ret;
2599
- }
2600
- else {
2601
- // We use two queries because of possible overlapping an IP and its network
2602
- if ( $ret = $wpdb->get_var( 'SELECT tag FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin <= ' . $long . ' AND ' . $long . ' <= ip_long_end AND tag = "W" LIMIT 1' ) ) {
2603
- $cache[ $key ] = $ret;
2604
- return $ret;
2605
- }
2606
- if ( $ret = $wpdb->get_var( 'SELECT tag FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin <= ' . $long . ' AND ' . $long . ' <= ip_long_end AND tag = "B" LIMIT 1' ) ) {
2607
- $cache[ $key ] = $ret;
2608
- return $ret;
2609
- }
2610
-
2611
- $cache[ $key ] = false;
2612
- return false;
2613
- }
2614
- }
2615
-
2616
- /**
2617
- * IPv6 version of cerber_acl_check() without subnets and ranges
2618
- *
2619
- * @param null $ip
2620
- * @param string $tag
2621
- *
2622
- * @return bool|null|string
2623
- */
2624
- function cerber_acl_checkV6( $ip = null, $tag = '' ) {
2625
- global $wpdb, $wp_cerber;
2626
- if ( ! $ip ) {
2627
- $ip = $wp_cerber->getRemoteIp();
2628
- }
2629
- if ( $tag ) {
2630
- if ( $wpdb->get_var( $wpdb->prepare( 'SELECT count(ip) FROM ' . CERBER_ACL_TABLE . ' WHERE ip = %s AND tag = %s', $ip, $tag ) ) ) {
2631
- return true;
2632
- }
2633
-
2634
- return false;
2635
- } else {
2636
- if ( $ret = $wpdb->get_var( $wpdb->prepare( 'SELECT tag FROM ' . CERBER_ACL_TABLE . ' WHERE ip = %s', $ip ) ) ) {
2637
- return $ret;
2638
- }
2639
-
2640
- return false;
2641
- }
2642
- }
2643
-
2644
-
2645
- function crb_acl_is_white( $ip = null ){
2646
-
2647
- $acl = cerber_acl_check( $ip );
2648
- if ( $acl == 'W' ) {
2649
- return true;
2650
- }
2651
-
2652
- return false;
2653
- }
2654
-
2655
- /*
2656
- * Logging directly to the file
2657
- *
2658
- * CERBER_FAIL_LOG optional, full path including filename to the log file
2659
- * CERBER_LOG_FACILITY optional, use to specify what type of program is logging the messages
2660
- *
2661
- * */
2662
- function cerber_file_log( $user_login, $ip ) {
2663
- if ( defined( 'CERBER_FAIL_LOG' ) ) {
2664
- if ( $log = @fopen( CERBER_FAIL_LOG, 'a' ) ) {
2665
- $pid = absint( @posix_getpid() );
2666
- @fwrite( $log, date( 'M j H:i:s ' ) . $_SERVER['SERVER_NAME'] . ' Cerber(' . $_SERVER['HTTP_HOST'] . ')[' . $pid . ']: Authentication failure for ' . $user_login . ' from ' . $ip . "\n" );
2667
- @fclose( $log );
2668
- }
2669
- } else {
2670
- @openlog( 'Cerber(' . $_SERVER['HTTP_HOST'] . ')', LOG_NDELAY | LOG_PID, defined( 'CERBER_LOG_FACILITY' ) ? CERBER_LOG_FACILITY : LOG_AUTH );
2671
- @syslog( LOG_NOTICE, 'Authentication failure for ' . $user_login . ' from ' . $ip );
2672
- @closelog();
2673
- }
2674
- }
2675
-
2676
- /*
2677
- Return wildcard - string like subnet Class C
2678
- */
2679
- function cerber_get_subnet( $ip ) {
2680
- return preg_replace( '/\.\d{1,3}$/', '.*', $ip );
2681
- }
2682
-
2683
- /*
2684
- Check if given IP address or wildcard or CIDR is valid
2685
- */
2686
- function cerber_is_ip_or_net( $ip ) {
2687
- if ( filter_var( $ip, FILTER_VALIDATE_IP ) ) {
2688
- return true;
2689
- }
2690
- // WILDCARD: 192.168.1.*
2691
- $ip = str_replace( '*', '0', $ip );
2692
- //if ( @inet_pton( $ip ) ) {
2693
- if ( filter_var( $ip, FILTER_VALIDATE_IP ) ) {
2694
- return true;
2695
- }
2696
- // CIDR: 192.168.1/24
2697
- if ( strpos( $ip, '/' ) ) {
2698
- $cidr = explode( '/', $ip );
2699
- $net = $cidr[0];
2700
- $mask = absint( $cidr[1] );
2701
- $dots = substr_count( $net, '.' );
2702
- if ( $dots < 3 ) {
2703
- if ( $dots == 1 ) {
2704
- $net .= '.0.0';
2705
- } elseif ( $dots == 2 ) {
2706
- $net .= '.0';
2707
- }
2708
- }
2709
- if ( ! cerber_is_ipv4( $net ) ) {
2710
- return false;
2711
- }
2712
- if ( ! is_numeric( $mask ) ) {
2713
- return false;
2714
- }
2715
-
2716
- return true;
2717
- }
2718
-
2719
- return false;
2720
- }
2721
-
2722
- /**
2723
- * Tries to recognize single IP address or IP v4 range (with dash) in a given string.
2724
- *
2725
- * @param string $string String to recognize IP address in
2726
- *
2727
- * @return array|bool|string Return single IP address or wildcard or CIDR as a string, and IP range as an array.
2728
- */
2729
- function cerber_parse_ip( $string = '' ) {
2730
- $string = trim( $string );
2731
- if ( cerber_is_ip_or_net( $string ) ) {
2732
- return $string;
2733
- }
2734
- $explode = explode( '-', $string );
2735
- if ( ! is_array( $explode ) || ! $explode ) {
2736
- return false;
2737
- }
2738
- $range = array();
2739
- $count = 0;
2740
- foreach ( $explode as $ip ) {
2741
- $ip = trim( $ip );
2742
- if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) ) {
2743
- $range[] = $ip;
2744
- $count ++;
2745
- if ( $count >= 2 ) {
2746
- break;
2747
- }
2748
- }
2749
- }
2750
- if ( count( $range ) < 2 ) {
2751
- return false;
2752
- }
2753
- if ( ip2long( $range[1] ) <= ip2long( $range[0] ) ) {
2754
- return false;
2755
- }
2756
-
2757
- return array(
2758
- 'range' => $range[0] . ' - ' . $range[1],
2759
- 'begin_ip' => $range[0],
2760
- 'end_ip' => $range[1],
2761
- 'begin' => ip2long( $range[0] ),
2762
- 'end' => ip2long( $range[1] ),
2763
- );
2764
- }
2765
-
2766
- /**
2767
- * Convert a network wildcard string like x.x.x.* to an IP v4 range
2768
- *
2769
- * @param $wildcard string
2770
- *
2771
- * @return array|bool|string False if no wildcard found, otherwise result of cerber_parse_ip()
2772
- */
2773
- function cerber_wildcard2range( $wildcard = '' ) {
2774
- $begin = str_replace( '*', '0', $wildcard );
2775
- $end = str_replace( '*', '255', $wildcard );
2776
- if ( ! cerber_is_ipv4( $begin ) ) {
2777
- return false;
2778
- }
2779
- if ( ! cerber_is_ipv4( $end ) ) {
2780
- return false;
2781
- }
2782
-
2783
- return cerber_parse_ip( $begin . ' - ' . $end );
2784
- }
2785
-
2786
- /**
2787
- * Convert a CIDR to an IP v4 range
2788
- *
2789
- * @param $cidr string
2790
- *
2791
- * @return array|bool|string
2792
- */
2793
- function cerber_cidr2range( $cidr = '' ) {
2794
- if ( ! strpos( $cidr, '/' ) ) {
2795
- return false;
2796
- }
2797
- $cidr = explode( '/', $cidr );
2798
- $net = $cidr[0];
2799
- $mask = absint( $cidr[1] );
2800
- $dots = substr_count( $net, '.' );
2801
- if ( $dots < 3 ) { // not completed CIDR
2802
- if ( $dots == 1 ) {
2803
- $net .= '.0.0';
2804
- } elseif ( $dots == 2 ) {
2805
- $net .= '.0';
2806
- }
2807
- }
2808
- if ( ! cerber_is_ipv4( $net ) ) {
2809
- return false;
2810
- }
2811
- if ( ! is_numeric( $mask ) ) {
2812
- return false;
2813
- }
2814
- $begin = long2ip( ( ip2long( $net ) ) & ( ( - 1 << ( 32 - (int) $mask ) ) ) );
2815
- $end = long2ip( ( ip2long( $net ) ) + pow( 2, ( 32 - (int) $mask ) ) - 1 );
2816
-
2817
- return cerber_parse_ip( $begin . ' - ' . $end );
2818
- }
2819
-
2820
- /**
2821
- * Try to recognize an IP range or a single IP in a string.
2822
- *
2823
- * @param $string string Network wildcard, CIDR or IP range.
2824
- *
2825
- * @return array|bool|string
2826
- */
2827
- function cerber_any2range( $string = '' ) {
2828
- // Do not change the order!
2829
- $ret = cerber_wildcard2range( $string );
2830
- if ( ! $ret ) {
2831
- $ret = cerber_cidr2range( $string );
2832
- }
2833
- if ( ! $ret ) {
2834
- $ret = cerber_parse_ip( $string ); // must be last due to checking for cidr and wildcard
2835
- }
2836
-
2837
- return $ret;
2838
- }
2839
-
2840
- /*
2841
- Check for given IP address or subnet belong to this session.
2842
- */
2843
- function cerber_is_myip( $ip ) {
2844
- global $wp_cerber;
2845
- if ( ! is_string( $ip ) ) {
2846
- return false;
2847
- }
2848
- $remote_ip = $wp_cerber->getRemoteIp();
2849
- if ( $ip == $remote_ip ) {
2850
- return true;
2851
- }
2852
- if ( $ip == cerber_get_subnet( $remote_ip ) ) {
2853
- return true;
2854
- }
2855
-
2856
- return false;
2857
- }
2858
-
2859
- function cerber_is_ip_in_range( $range, $ip = null ) {
2860
- global $wp_cerber;
2861
- if ( ! is_array( $range ) ) {
2862
- return false;
2863
- }
2864
- if ( ! $ip ) {
2865
- $ip = $wp_cerber->getRemoteIp();
2866
- }
2867
- $long = ip2long( $ip );
2868
- if ( $range['begin'] <= $long && $long <= $range['end'] ) {
2869
- return true;
2870
- }
2871
-
2872
- return false;
2873
- }
2874
-
2875
- /**
2876
- * Display 404 page to bump bots and bad guys
2877
- *
2878
- * @param bool $simple If true force displaying basic 404 page
2879
- */
2880
- function cerber_404_page($simple = false) {
2881
- global $wp_query;
2882
-
2883
- if ( !$simple ) {
2884
- if ( function_exists( 'status_header' ) ) {
2885
- status_header( '404' );
2886
- }
2887
- if ( $wp_query && is_object( $wp_query ) ) {
2888
- $wp_query->set_404();
2889
- }
2890
- if ( 0 == crb_get_settings( 'page404' ) ) {
2891
- $template = null;
2892
- if ( function_exists( 'get_404_template' ) ) {
2893
- $template = get_404_template();
2894
- }
2895
- if ( function_exists( 'apply_filters' ) ) {
2896
- $template = apply_filters( 'cerber_404_template', $template );
2897
- }
2898
- if ( $template && @file_exists( $template ) ) {
2899
- include( $template );
2900
- exit;
2901
- }
2902
- }
2903
- }
2904
-
2905
- header( 'HTTP/1.0 404 Not Found', true, 404 );
2906
- echo '<html><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL ' . esc_url( $_SERVER['REQUEST_URI'] ) . ' was not found on this server.</p></body></html>';
2907
- cerber_traffic_log(); // do not remove!
2908
- exit;
2909
- }
2910
- /*
2911
- Display Forbidden page
2912
- */
2913
- function cerber_forbidden_page() {
2914
- status_header( '403' );
2915
- header( 'HTTP/1.0 403 Access Forbidden', true, 403 );
2916
- ?>
2917
- <!DOCTYPE html>
2918
- <html style="height: 100%;">
2919
- <meta charset="UTF-8">
2920
- <head><title>403 Access Forbidden</title></head>
2921
- <body style="height: 100%;">
2922
- <div style="display: flex; align-items: center; justify-content: center; height: 70%;">
2923
- <div style="background-color: #eee; width: 70%; border: solid 3px #ddd; padding: 1.5em 3em 3em 3em; font-family: Arial, Helvetica, sans-serif;">
2924
- <div style="display: table-row;">
2925
- <div style="display: table-cell; font-size: 150px; color: red; vertical-align: middle; padding-right: 50px;">
2926
- &#9995;
2927
- </div>
2928
- <div style="display: table-cell; vertical-align: middle;">
2929
- <h1><?php _e("We're sorry, you are not allowed to proceed", 'wp-cerber'); ?></h1>
2930
- <p>Our server stopped processing your request. Your request looks suspicious or similar to automated
2931
- requests from spam posting software.</p>
2932
- <p>If you believe you should be able to perform this request, please let us know.</p>
2933
- </div>
2934
- </div>
2935
- </div>
2936
- </div>
2937
- </body>
2938
- </html>
2939
- <?php
2940
- cerber_traffic_log(); // do not remove!
2941
- exit;
2942
- }
2943
-
2944
- // Citadel mode -------------------------------------------------------------------------------------
2945
-
2946
- function cerber_enable_citadel() {
2947
- global $wp_cerber;
2948
- if ( get_transient( 'cerber_citadel' ) ) {
2949
- return;
2950
- }
2951
- set_transient( 'cerber_citadel', true, crb_get_settings( 'ciduration' ) * 60 );
2952
- cerber_log( 12 );
2953
-
2954
- // Notify admin
2955
- if ( $wp_cerber->getSettings( 'cinotify' ) ) {
2956
- cerber_send_notify( 'citadel' );
2957
- }
2958
- }
2959
-
2960
- function cerber_disable_citadel() {
2961
- delete_transient( 'cerber_citadel' );
2962
- }
2963
-
2964
- function cerber_is_citadel() {
2965
- if ( get_transient( 'cerber_citadel' ) ) {
2966
- return true;
2967
- }
2968
-
2969
- return false;
2970
- }
2971
-
2972
- // Hardening -------------------------------------------------------------------------------------
2973
-
2974
- //if (!cerber_acl_check(cerber_get_ip(),'W') && false) {
2975
-
2976
- /*
2977
- if ($hardening['ping']) {
2978
- add_filter( 'xmlrpc_methods', 'remove_xmlrpc_pingback' );
2979
- function remove_xmlrpc_pingback( $methods ) {
2980
- unset($methods['pingback.ping']);
2981
- unset($methods['pingback.extensions.getPingbacks']);
2982
- return $methods;
2983
- }
2984
- add_filter( 'wp_headers', 'remove_pingback_header' );
2985
- function remove_pingback_header( $headers ) {
2986
- unset( $headers['X-Pingback'] );
2987
- return $headers;
2988
- }
2989
- }
2990
- */
2991
- //pingback_ping();
2992
-
2993
-
2994
- /*
2995
- // Remove shortlink from HEAD <link rel='shortlink' href='http://адрес-сайта/?p=45' />
2996
- remove_action('wp_head', 'wp_shortlink_wp_head', 10, 0 );
2997
- */
2998
-
2999
- /**
3000
- *
3001
- * Send notification letter
3002
- *
3003
- * @param string $type Notification type
3004
- * @param string|array $msg Additional message
3005
- * @param string $ip Remote IP address, if applicable
3006
- *
3007
- * @return bool
3008
- */
3009
- function cerber_send_notify( $type = '', $msg = '', $ip = '' ) {
3010
- global $wpdb, $wp_cerber;
3011
- if ( ! $type ) {
3012
- return false;
3013
- }
3014
-
3015
- /*
3016
- $super = false;
3017
- if ( function_exists( 'is_super_admin' ) ) {
3018
- $super = is_super_admin();
3019
- }
3020
- if ( $type == 'lockout' && !$usper()) {
3021
- */
3022
-
3023
- if ( $type == 'lockout' && !is_admin()) {
3024
- $rate = absint( $wp_cerber->getSettings( 'emailrate' ) );
3025
- if ( $rate ) {
3026
- $last = get_transient( 'cerber_last' );
3027
- $period = 60 * 60; // per hour
3028
- if ( $last ) {
3029
- if ( $last > ( time() - $period / $rate ) ) {
3030
- return false;
3031
- }
3032
- }
3033
- set_transient( 'cerber_last', time(), $period );
3034
- }
3035
- }
3036
-
3037
- $html_mode = false;
3038
-
3039
- $subj = '[' . get_option( 'blogname' ) . '] ' . __( 'WP Cerber notify', 'wp-cerber' ) . ': ';
3040
- $body = '';
3041
-
3042
- if ( is_array( $msg ) ) {
3043
- $msg = implode( "\n\n", $msg );
3044
- }
3045
-
3046
- switch ( $type ) {
3047
- case 'citadel':
3048
- $max = $wpdb->get_var( 'SELECT MAX(stamp) FROM ' . CERBER_LOG_TABLE . ' WHERE activity = 7' );
3049
- if ($max) {
3050
- $last_date = cerber_date( $max );
3051
- $last = $wpdb->get_row( 'SELECT * FROM ' . CERBER_LOG_TABLE . ' WHERE stamp = ' . $max . ' AND activity = 7' );
3052
- }
3053
- else $last = null;
3054
-
3055
- if ( ! $last ) { // workaround for the empty log table
3056
- $last = new stdClass();
3057
- $last->ip = '127.0.0.1';
3058
- $last->user_login = 'test';
3059
- }
3060
-
3061
- $subj .= __( 'Citadel mode is activated', 'wp-cerber' );
3062
-
3063
- $body = sprintf( __( 'Citadel mode is activated after %d failed login attempts in %d minutes.', 'wp-cerber' ), $wp_cerber->getSettings( 'cilimit' ), $wp_cerber->getSettings( 'ciperiod' ) ) . "\n\n";
3064
- $body .= sprintf( __( 'Last failed attempt was at %s from IP %s with user login: %s.', 'wp-cerber' ), $last_date, $last->ip, $last->user_login ) . "\n\n";
3065
- $body .= __( 'View activity in dashboard', 'wp-cerber' ) . ': ' . cerber_admin_link( 'activity' ) . "\n\n";
3066
- //$body .= __('Change notification settings','wp-cerber').': '.cerber_admin_link();
3067
- break;
3068
- case 'lockout':
3069
- $max = $wpdb->get_var( 'SELECT MAX(stamp) FROM ' . CERBER_LOG_TABLE . ' WHERE activity IN (10,11)' );
3070
- if ($max){
3071
- $last_date = cerber_date( $max );
3072
- $last = $wpdb->get_row( 'SELECT * FROM ' . CERBER_LOG_TABLE . ' WHERE stamp = ' . $max . ' AND activity IN (10,11)' );
3073
- }
3074
- else $last = null;
3075
- if ( ! $last ) { // workaround for the empty log table
3076
- $last = new stdClass();
3077
- $last->ip = '127.0.0.1';
3078
- $last->user_login = 'test';
3079
- }
3080
-
3081
- //if ( ! $active = $wpdb->get_var( 'SELECT count(ip) FROM ' . CERBER_BLOCKS_TABLE ) ) {
3082
- if ( ! $active = cerber_blocked_num() ) {
3083
- $active = 0;
3084
- }
3085
- //if ( $ip && ( $block = cerber_get_block( $ip ) ) ) {
3086
- if ( $last->ip && ( $block = cerber_get_block( $last->ip ) ) ) {
3087
- $reason = $block->reason;
3088
- }
3089
- else {
3090
- $reason = __( 'unspecified', 'wp-cerber' );
3091
- }
3092
-
3093
- $subj .= __( 'Number of lockouts is increasing', 'wp-cerber' ) . ' (' . $active . ')';
3094
-
3095
- $body = __( 'Number of active lockouts', 'wp-cerber' ) . ': ' . $active . "\n\n";
3096
- $body .= sprintf( __( 'Last lockout was added: %s for IP %s', 'wp-cerber' ), $last_date, $last->ip . ' (' . @gethostbyaddr( $last->ip ) . ')' ) . "\n\n";
3097
- $body .= __( 'Reason', 'wp-cerber' ) . ': ' . strip_tags($reason) . "\n\n";
3098
- $body .= __( 'View activity for this IP', 'wp-cerber' ) . ': ' . cerber_admin_link( 'activity' ) . '&filter_ip=' . $last->ip . "\n\n";
3099
- $body .= __( 'View lockouts in dashboard', 'wp-cerber' ) . ': ' . cerber_admin_link( 'lockouts' ) . "\n\n";
3100
- break;
3101
- case 'new_version':
3102
- $subj = __( 'A new version of WP Cerber is available to install', 'wp-cerber' );
3103
- $body = __( 'Hi!', 'wp-cerber' ) . "\n\n";
3104
- $body .= __( 'A new version of WP Cerber is available to install', 'wp-cerber' ) . "\n\n";
3105
- $body .= $msg . "\n\n";
3106
- $body .= __( 'Website', 'wp-cerber' ) . ': ' . get_bloginfo( 'name' );
3107
- break;
3108
- case 'shutdown':
3109
- $subj = '[' . get_option( 'blogname' ) . '] ' . __( 'The WP Cerber security plugin has been deactivated', 'wp-cerber' );
3110
- $body .= __( 'The WP Cerber security plugin has been deactivated', 'wp-cerber' ) . "\n\n";
3111
- if ( ! is_user_logged_in() ) {
3112
- $u = __( 'Not logged in', 'wp-cerber' );
3113
- } else {
3114
- $user = wp_get_current_user();
3115
- $u = $user->display_name;
3116
- }
3117
- $body .= __( 'Website', 'wp-cerber' ) . ': ' . get_bloginfo( 'name' ) . "\n";
3118
- $body .= __( 'By user', 'wp-cerber' ) . ': ' . $u . "\n";
3119
- $body .= __( 'From IP address', 'wp-cerber' ) . ': ' . $wp_cerber->getRemoteIp() . "\n";
3120
- $whois = cerber_ip_whois_info( $wp_cerber->getRemoteIp() );
3121
- if ( ! empty( $whois['data']['country'] ) ) {
3122
- $body .= __( 'From country', 'wp-cerber' ) . ': ' . cerber_country_name( $whois['data']['country'] );
3123
- }
3124
- break;
3125
- case 'activated':
3126
- $subj = '[' . get_option( 'blogname' ) . '] ' . __( 'The WP Cerber security plugin is now active', 'wp-cerber' );
3127
- $body .= __( 'WP Cerber is now active and has started protecting your site', 'wp-cerber' ) . "\n\n";
3128
- //$body .= __( 'Change notification settings', 'wp-cerber' ) . ': ' . cerber_admin_link('notifications') . "\n\n";
3129
- $body .= __( 'Getting Started Guide', 'wp-cerber' ) . "\n\n";
3130
- $body .= 'https://wpcerber.com/getting-started/' . "\n\n";
3131
- $body .= 'Be in touch with the developer. Subscribe to Cerber\'s newsletter: http://wpcerber.com/subscribe-newsletter/';
3132
- //$body .= get_bloginfo( 'name' );
3133
- break;
3134
- case 'newlurl':
3135
- $subj .= __( 'New Custom login URL', 'wp-cerber' );
3136
- $body .= $msg;
3137
- break;
3138
- case 'subs':
3139
- $subj .= __( 'A new activity has been recorded', 'wp-cerber' );
3140
- $body = __( 'A new activity has been recorded', 'wp-cerber' ) . "\n\n";
3141
- $body .= $msg;
3142
- break;
3143
- case 'report':
3144
- $html_mode = true;
3145
- $subj = '[' . get_option( 'blogname' ) . '] WP Cerber Security: ' . __( 'Weekly report', 'wp-cerber' );
3146
- $body = cerber_generate_report();
3147
- $link = cerber_admin_link( 'notifications' );
3148
- $body .= '<br/>' . __( 'To change reporting settings visit', 'wp-cerber' ) . ' <a href="' . $link . '">' . $link . '</a>';
3149
- if ($msg) {
3150
- $body .= nl2br($msg);
3151
- }
3152
- break;
3153
- }
3154
-
3155
- $to_list = cerber_get_email( $type, true );
3156
- $to = implode( ', ', $to_list );
3157
-
3158
- $body_filtered = apply_filters( 'cerber_notify_body', $body, array( 'type' => $type,
3159
- 'IP' => $ip,
3160
- 'to' => $to,
3161
- 'subject' => $subj
3162
- ) );
3163
- if ( $body_filtered && is_string( $body_filtered ) ) {
3164
- $body = $body_filtered;
3165
- }
3166
-
3167
- $footer = '';
3168
-
3169
- if ( $lolink = cerber_get_login_url() ) {
3170
- $lourl = urldecode( $lolink );
3171
- if ( $html_mode ) {
3172
- $lourl = '<a href="' . $lolink . '">' . $lourl . '</a>';
3173
- }
3174
- $footer .= "\n\n" . __( 'Your login page:', 'wp-cerber' ) . ' ' . $lourl;
3175
- }
3176
-
3177
- if ( $type == 'report' && $date = lab_lab(true) ) {
3178
- $footer .= "\n\n" . __( 'Your license is valid until', 'wp-cerber' ) . ' ' . $date;
3179
- }
3180
-
3181
- $footer .= "\n\n\n" . __( 'This message was sent by', 'wp-cerber' ) . ' WP Cerber Security ' . CERBER_VER . "\n";
3182
- $footer .= 'https://wpcerber.com';
3183
-
3184
- if ( $html_mode ) {
3185
- add_filter( 'wp_mail_content_type', 'cerber_enable_html' );
3186
- $footer = str_replace( "\n", '<br/>', $footer );
3187
- }
3188
-
3189
- // Everything is prepared, let's send it out
3190
-
3191
- $result = null;
3192
- if ( $to && $subj && $body ) {
3193
- if ( ! $html_mode ) {
3194
- cerber_pb_send( $subj, $body.$footer );
3195
- }
3196
-
3197
- if ( $type == 'report') {
3198
- $result = true;
3199
- foreach ( $to_list as $email ) {
3200
- $lastus = '';
3201
- if ( $rec = cerber_get_last_login( null, $email ) ) {
3202
- $lastus = sprintf( __( 'Your last sign-in was %s from %s', 'wp-cerber' ), cerber_date( $rec->stamp ), $rec->ip . ' (' . cerber_country_name( $rec->country ) . ')' );
3203
- if ( $html_mode ) {
3204
- $lastus = '<br/><br/>' . $lastus;
3205
- }
3206
- else {
3207
- $lastus = "\n\n" . $lastus;
3208
- }
3209
- }
3210
-
3211
- if ( ! wp_mail( $email, $subj, '<html>' . $body . $lastus . $footer . '</html>' ) ) {
3212
- $result = false;
3213
- }
3214
- }
3215
- }
3216
- else {
3217
- if ( function_exists( 'wp_mail' ) ) {
3218
- $body = $body . $footer;
3219
- if ( $html_mode ) {
3220
- $body = '<html>' . $body . '</html>';
3221
- }
3222
- $result = wp_mail( $to, $subj, $body );
3223
- }
3224
- }
3225
- }
3226
-
3227
- remove_filter('wp_mail_content_type', 'cerber_enable_html');
3228
-
3229
- $params = array( 'type' => $type, 'IP' => $ip, 'to' => $to, 'subject' => $subj );
3230
- if ( $result ) {
3231
- do_action( 'cerber_notify_sent', $body, $params );
3232
- }
3233
- else {
3234
- do_action( 'cerber_notify_fail', $body, $params );
3235
- }
3236
-
3237
- return $result;
3238
- }
3239
-
3240
- function cerber_enable_html() {
3241
- return 'text/html';
3242
- }
3243
-
3244
- /**
3245
- * Generates a performance report
3246
- *
3247
- * @param int $period Days to look back
3248
- *
3249
- * @return string
3250
- */
3251
- function cerber_generate_report($period = 7){
3252
- global $wpdb;
3253
-
3254
- $period = absint( $period );
3255
-
3256
- if ( ! $period ) {
3257
- $period = 7;
3258
- }
3259
-
3260
- $ret = '';
3261
- $rows = array();
3262
- $stamp = time() - $period * 24 * 3600;
3263
- //$in = implode( ',', crb_get_activity_set( 'malicious' ) );
3264
- //$link_base = '<a href="' . cerber_activity_link( array( 2 ) ) . '">';
3265
- $base_url = cerber_admin_link( 'activity' );
3266
- $css_table = 'width: 95%; max-width: 1000px; margin:0 auto; margin-bottom: 10px; background-color: #f5f5f5; text-align: center;';
3267
- $css_td = 'padding: 0.5em 0.5em 0.5em 1em; text-align: left;';
3268
- $css_boder = 'border-bottom: solid 2px #f9f9f9;';
3269
-
3270
- if (is_multisite()) {
3271
- $site_name = get_site_option( 'site_name' );
3272
- }
3273
- else {
3274
- $site_name = get_option( 'blogname' );
3275
- }
3276
-
3277
- $ret .= '<div style="' . $css_table . '"><div style="margin:0 auto; text-align: center;"><p style="font-size: 130%; padding-top: 0.5em;">' . $site_name .'</p><p style="padding-bottom: 1em;">'. __('Weekly Report','wp-cerber'). '</p></div></div>';
3278
-
3279
- $kpi_list = cerber_calculate_kpi( $period );
3280
-
3281
- foreach ($kpi_list as $kpi){
3282
- $rows[] = '<td style="'.$css_td.' text-align: right;">'.$kpi[1].'</td><td style="padding: 0.5em; text-align: left;">'.$kpi[0].'</td>';
3283
- }
3284
-
3285
- $ret .= '<div style="text-align: center; '.$css_table.'"><table style="font-size: 130%; margin:0 auto;"><tr>' . implode( '</tr><tr>', $rows ) . '</tr></table></div>';
3286
-
3287
- // Activities counters
3288
- $rows = array();
3289
- $rows[] = '<td style="'.$css_td.$css_boder.'" colspan="2"><p style="line-height: 1.5em; font-weight: bold;">'.__('Activity details','wp-cerber').'</p></td>';
3290
- $activites = $wpdb->get_results( 'SELECT activity, COUNT(activity) cnt FROM ' . CERBER_LOG_TABLE . ' WHERE stamp > ' . $stamp . ' GROUP by activity ORDER BY cnt DESC' );
3291
- if ( $activites ) {
3292
- $lables = cerber_get_labels();
3293
- foreach ( $activites as $a ) {
3294
- $rows[] = '<td style="'.$css_boder.$css_td.'">' . $lables[ $a->activity ] . '</td><td style="padding: 0.5em; text-align: center; width:10%;'.$css_boder.'"><a href="'.$base_url.'&filter_activity='.$a->activity.'">' . $a->cnt . '</a></td>';
3295
- }
3296
- }
3297
- $ret .= '<table style="border-collapse: collapse; '.$css_table.'"><tr>' . implode( '</tr><tr>', $rows ) . '</tr></table>';
3298
-
3299
- // Activities counters
3300
- $activites = $wpdb->get_results( 'SELECT user_login, COUNT(user_login) cnt FROM ' . CERBER_LOG_TABLE . ' WHERE activity = 51 AND stamp > ' . $stamp . ' GROUP by user_login ORDER BY cnt DESC LIMIT 10' );
3301
- if ( $activites ) {
3302
- $rows = array();
3303
- $rows[] = '<td style="'.$css_td.$css_boder.'" colspan="2"><p style="line-height: 1.5em; font-weight: bold;">'.__('Attempts to log in with non-existent username','wp-cerber').'</p></td>';
3304
- foreach ( $activites as $a ) {
3305
- $rows[] = '<td style="'.$css_boder.$css_td.'">' . htmlspecialchars($a->user_login) . '</td><td style="padding: 0.5em; text-align: center; width:10%;'.$css_boder.'"><a href="'.$base_url.'&filter_login='.$a->user_login.'">' . $a->cnt . '</a></td>';
3306
- }
3307
- $ret .= '<table style="border-collapse: collapse; '.$css_table.'"><tr>' . implode( '</tr><tr>', $rows ) . '</tr></table>';
3308
- }
3309
-
3310
- $ret = '<div style="width:100%; padding: 1em; text-align: center; background-color: #f9f9f9;">' . $ret . '</div>';
3311
-
3312
- return $ret;
3313
- }
3314
-
3315
-
3316
- // Maintenance routines ----------------------------------------------------------------
3317
-
3318
- function cerber_init_cron(){
3319
- $next_hour = floor( ( time() + 3600 ) / 3600 ) * 3600;
3320
-
3321
- if ( ! wp_next_scheduled( 'cerber_hourly_1' ) ) {
3322
- wp_schedule_event( $next_hour + 600, 'hourly', 'cerber_hourly_1' );
3323
- }
3324
-
3325
- if ( ! wp_next_scheduled( 'cerber_hourly_2' ) ) {
3326
- wp_schedule_event( $next_hour , 'hourly', 'cerber_hourly_2' );
3327
- }
3328
-
3329
- if ( ! wp_next_scheduled( 'cerber_daily' ) ) {
3330
- wp_schedule_event( $next_hour + 3600, 'daily', 'cerber_daily' );
3331
- }
3332
- }
3333
-
3334
- add_action( 'cerber_hourly_1', 'cerber_do_hourly' );
3335
- function cerber_do_hourly($force = false) {
3336
- global $wpdb, $wp_cerber;
3337
-
3338
- if (is_multisite()) {
3339
- if ( ! $force && get_site_transient( 'cerber_multisite' ) ) {
3340
- return;
3341
- }
3342
- set_site_transient( 'cerber_multisite', 'executed', 3600 );
3343
- }
3344
-
3345
- if ( crb_get_settings( 'cerberlab' ) ) {
3346
- lab_check_nodes();
3347
- }
3348
-
3349
- $time = time();
3350
- $days = absint( crb_get_settings( 'keeplog' ) );
3351
- if ( $days > 0 ) {
3352
- $wpdb->query( 'DELETE FROM ' . CERBER_LOG_TABLE . ' WHERE stamp < ' . ( $time - $days * 24 * 3600 ) );
3353
- }
3354
- $days = absint( crb_get_settings( 'tikeeprec' ) );
3355
- if ( $days > 0 ) {
3356
- $wpdb->query( 'DELETE FROM ' . CERBER_TRAF_TABLE . ' WHERE stamp < ' . ( $time - $days * 24 * 3600 ) );
3357
- }
3358
-
3359
- if ( crb_get_settings( 'cerberlab' ) ) {
3360
- cerber_push_lab();
3361
- }
3362
-
3363
- $wpdb->query( 'DELETE FROM ' . CERBER_LAB_IP_TABLE . ' WHERE expires < ' . $time );
3364
-
3365
- if ( $wp_cerber->getSettings( 'trashafter-enabled') && absint($wp_cerber->getSettings('trashafter'))) {
3366
- $list = get_comments( array( 'status' => 'spam' ) );
3367
- if ( $list ) {
3368
- $time = time() - DAY_IN_SECONDS * absint($wp_cerber->getSettings( 'trashafter' ));
3369
- foreach ( $list as $item ) {
3370
- if ( $time > strtotime( $item->comment_date_gmt ) ) {
3371
- wp_trash_comment( $item->comment_ID );
3372
- }
3373
- }
3374
- }
3375
- }
3376
-
3377
- cerber_up_data();
3378
-
3379
- set_site_transient( 'crb_hourly_1', date( 'G' ) , 3600 );
3380
- }
3381
-
3382
- add_action( 'cerber_hourly_2', function () {
3383
-
3384
- // Avoid multiple executions on a weird hosting
3385
- if ( ( $hour = get_site_transient( 'crb_hourly_2' ) ) && $hour == date( 'G' ) ) {
3386
- return;
3387
- }
3388
-
3389
- $gmt_offset = get_option( 'gmt_offset' ) * 3600;
3390
-
3391
- if ( crb_get_settings( 'enable-report' )
3392
- && date( 'w', time() + $gmt_offset ) == crb_get_settings( 'wreports-day' )
3393
- && date( 'G', time() + $gmt_offset ) == crb_get_settings( 'wreports-time' )
3394
- //&& ! get_site_transient( 'cerber_wreport' )
3395
- ) {
3396
- $result = cerber_send_notify( 'report' );
3397
- //set_site_transient( 'cerber_wreport', 'sent', 7200 );
3398
- update_site_option( '_cerber_report', array( time(), $result ) );
3399
- }
3400
-
3401
- cerber_watchdog( true );
3402
-
3403
- set_site_transient( 'crb_hourly_2', date( 'G' ) , 3600 );
3404
- });
3405
-
3406
- add_action( 'cerber_daily', 'cerber_do_daily' );
3407
- function cerber_do_daily() {
3408
- global $wpdb, $wp_cerber;
3409
-
3410
- cerber_do_hourly( true );
3411
-
3412
- $time = time();
3413
-
3414
- lab_trunc_push();
3415
-
3416
- lab_validate_lic();
3417
-
3418
- $wpdb->query( 'DELETE FROM ' . CERBER_LAB_NET_TABLE . ' WHERE expires < ' . $time );
3419
-
3420
- $wpdb->query( 'OPTIMIZE TABLE ' . CERBER_LOG_TABLE );
3421
- $wpdb->query( 'OPTIMIZE TABLE ' . CERBER_TRAF_TABLE );
3422
- $wpdb->query( 'OPTIMIZE TABLE ' . CERBER_ACL_TABLE );
3423
- $wpdb->query( 'OPTIMIZE TABLE ' . CERBER_BLOCKS_TABLE );
3424
- $wpdb->query( 'OPTIMIZE TABLE ' . CERBER_LAB_TABLE );
3425
- $wpdb->query( 'OPTIMIZE TABLE ' . CERBER_LAB_IP_TABLE );
3426
- $wpdb->query( 'OPTIMIZE TABLE ' . CERBER_LAB_NET_TABLE );
3427
-
3428
- if ( $new = cerber_check_version() ) {
3429
- $history = get_site_option( '_cerber_notify_new' );
3430
- if ( ! $history || ! is_array( $history ) ) {
3431
- $history = array();
3432
- }
3433
- if ( !in_array( $new['ver'], $history ) ) {
3434
- cerber_send_notify( 'new_version', 'Read more: https://wpcerber.com/?plugin_version=' . $new['ver'] );
3435
- $history[] = $new['ver'];
3436
- update_site_option( '_cerber_notify_new', $history );
3437
- }
3438
- }
3439
-
3440
- // TODO: implement holding previous values for a while
3441
- // cerber_antibot_gene();
3442
- }
3443
-
3444
- /*
3445
- Return system ID of the WP Cerber plugin
3446
- */
3447
- function cerber_plug_in() {
3448
- return plugin_basename( __FILE__ );
3449
- }
3450
-
3451
- /*
3452
- Return plugin info
3453
- */
3454
- function cerber_plugin_data() {
3455
- return get_plugin_data( __FILE__ );
3456
- }
3457
-
3458
- /*
3459
- Return main plugin file
3460
- */
3461
- function cerber_plugin_file() {
3462
- return __FILE__;
3463
- }
3464
-
3465
- /**
3466
- * Log activity
3467
- *
3468
- * @param int $activity Activity ID
3469
- * @param string $login Login used or any additional information
3470
- * @param int $user_id User ID
3471
- * @param null $ip IP Address
3472
- *
3473
- * @return false|int
3474
- * @since 3.0
3475
- */
3476
- function cerber_log( $activity, $login = '', $user_id = 0, $ip = null ) {
3477
- global $wpdb, $user_ID, $cerber_logged;
3478
- static $logged = array();
3479
- $wp_cerber = get_wp_cerber();
3480
-
3481
- if ( isset( $logged[ $activity ] ) ) {
3482
- return false;
3483
- }
3484
- else {
3485
- $logged[ $activity ] = true;
3486
- }
3487
-
3488
- $cerber_logged[$activity] = $activity;
3489
-
3490
- //$wp_cerber->setProcessed();
3491
-
3492
- if ( empty( $ip ) ) {
3493
- $ip = $wp_cerber->getRemoteIp();
3494
- }
3495
- if ( cerber_is_ipv4( $ip ) ) {
3496
- $ip_long = ip2long( $ip );
3497
- }
3498
- else {
3499
- $ip_long = 1;
3500
- }
3501
-
3502
- if ( empty( $user_id ) ) {
3503
- if ($user_ID) {
3504
- $user_id = absint($user_ID);
3505
- }
3506
- else $user_ID = 0;
3507
- }
3508
-
3509
- //$stamp = microtime( true );
3510
- $stamp = cerber_request_time();
3511
-
3512
- $pos = strpos($_SERVER['REQUEST_URI'],'?');
3513
- if ($pos) {
3514
- $path = substr( $_SERVER['REQUEST_URI'], 0, $pos );
3515
- }
3516
- else {
3517
- $path = $_SERVER['REQUEST_URI'];
3518
- }
3519
- $url = strip_tags($_SERVER['HTTP_HOST'] . $path);
3520
-
3521
- $why = 0;
3522
- if ($activity != 10 && $activity != 11) {
3523
- $why = cerber_get_status($ip);
3524
- }
3525
-
3526
- $details = $why .'|0|0|0|'. $url;
3527
-
3528
- $country = lab_get_country( $ip );
3529
-
3530
- $ret = $wpdb->query( $wpdb->prepare( 'INSERT INTO ' . CERBER_LOG_TABLE . ' (ip, ip_long, user_login, user_id, stamp, activity, session_id, country, details) VALUES (%s,%d,%s,%d,%f,%d,%s,%s,%s)', $ip, $ip_long, $login, $user_id, $stamp, $activity, $wp_cerber->getSessionID(), $country, $details ) );
3531
- if ( ! $ret ) {
3532
- // workaround for a WP bugs like this: WP silently doesn't not insert a row into a table
3533
- // https://core.trac.wordpress.org/ticket/32315
3534
- $ret = $wpdb->insert( CERBER_LOG_TABLE, array(
3535
- 'ip' => $ip,
3536
- 'ip_long' => $ip_long,
3537
- 'user_login' => $login,
3538
- 'user_id' => $user_id,
3539
- 'stamp' => $stamp,
3540
- 'activity' => $activity,
3541
- 'session_id' => $wp_cerber->getSessionID(),
3542
- 'country' => $country,
3543
- 'details' => $details,
3544
- ), array( '%s', '%d', '%s', '%d', '%f', '%d' ) );
3545
- }
3546
-
3547
- if ( ! $ret ) {
3548
- cerber_watchdog();
3549
- }
3550
-
3551
- // Subscriptions - notifications for admin ---------------------------------------------------
3552
-
3553
- $subs = cerber_get_site_option( '_cerber_subs' );
3554
-
3555
- if (!empty($subs)) {
3556
- foreach ( $subs as $hash => $sub ) {
3557
-
3558
- // Loop through subscription parameters
3559
- if ( ! empty( $sub[0] )) {
3560
- if ( ! in_array( $activity, $sub[0] ) ) {
3561
- continue;
3562
- }
3563
- }
3564
- if ( ! empty( $sub[1] ) && $sub[1] != $user_id ) {
3565
- continue;
3566
- }
3567
- if ( ! empty( $sub[3] ) && ( $ip_long < $sub[2] || $sub[3] < $ip_long ) ) {
3568
- continue;
3569
- }
3570
- if ( ! empty( $sub[4] ) && $sub[4] != $ip ) {
3571
- continue;
3572
- }
3573
- if ( ! empty( $sub[5] ) && $sub[5] != $login ) {
3574
- continue;
3575
- }
3576
- if ( ! empty( $sub[6] ) && (false === strpos( $ip, $sub[6] )) && (false === mb_strpos( $login, $sub[6] )) ) {
3577
- continue;
3578
- }
3579
-
3580
- // Some parameter(s) matched, prepare and send notification
3581
-
3582
- $labels = cerber_get_labels( 'activity' );
3583
-
3584
- $msg = __( 'Activity', 'wp-cerber' ) . ': ' . $labels[$activity] . "\n\n";
3585
-
3586
- if ( $country ) {
3587
- $coname = ' ('.cerber_country_name( $country ).')';
3588
- }
3589
- else {
3590
- $coname = '';
3591
- }
3592
-
3593
- $msg .= __( 'IP', 'wp-cerber' ) . ': ' . $ip . $coname. "\n\n";
3594
-
3595
- if ( $user_id && function_exists('get_userdata')) {
3596
- $u = get_userdata( $user_id );
3597
- $msg .= __( 'User', 'wp-cerber' ) . ': ' . $u->display_name . "\n\n";
3598
- }
3599
-
3600
- if ( $login ) {
3601
- $msg .= __( 'Username used', 'wp-cerber' ) . ': ' . $login . "\n\n";
3602
- }
3603
-
3604
- if ( ! empty( $sub['6'] ) ) {
3605
- $msg .= __( 'Search string', 'wp-cerber' ) . ': ' . $sub['6'] . "\n\n";
3606
- }
3607
-
3608
- // Link to the Activity admin page
3609
- $args = cerber_subscribe_params();
3610
- $i = 0;
3611
- $link_params = '';
3612
- foreach ($args as $arg => $val){
3613
- if (is_array($sub[$i])){
3614
- foreach ( $sub[ $i ] as $item ) {
3615
- $link_params .= '&' . $arg . '[]=' . $item;
3616
- }
3617
- }
3618
- else {
3619
- $link_params .= '&' . $arg . '=' . $sub[ $i ];
3620
- }
3621
- $i++;
3622
- }
3623
- $link = cerber_admin_link( 'activity' ) . $link_params;
3624
-
3625
- $msg .= __( 'View activity in dashboard', 'wp-cerber' ) . ': ' . $link;
3626
- $msg .= "\n\n" . __( 'To unsubscribe click here', 'wp-cerber' ) . ': ' . cerber_admin_link( 'activity' ) . '&unsubscribeme=' . $hash;
3627
-
3628
- cerber_send_notify( 'subs', $msg, $ip );
3629
-
3630
- break; // Just one notification letter per event
3631
- }
3632
- }
3633
-
3634
- if ( in_array( $activity, array( 16, 17, 40 ) ) ) {
3635
- lab_save_push( $ip, $activity, '' );
3636
- }
3637
-
3638
- return $ret;
3639
- }
3640
-
3641
- /**
3642
- * Get records from the log
3643
- *
3644
- * @param array $activity
3645
- * @param array $user
3646
- * @param array $order
3647
- * @param string $limit
3648
- *
3649
- * @return array|null
3650
- */
3651
- function cerber_get_log($activity = array(), $user = array(), $order = array(), $limit = ''){
3652
- global $wpdb;
3653
-
3654
- $where = array();
3655
- if ($activity){
3656
- $activity = array_map( 'absint', $activity );
3657
- $where[] = 'activity IN ('.implode(', ',$activity).')';
3658
- }
3659
-
3660
- if ($user['email']){
3661
- $user = get_user_by( 'email', $user['email'] );
3662
- $where[] = 'user_id = ' . absint( $user->ID );
3663
- }
3664
- elseif ($user['id']){
3665
- $where[] = 'user_id = '.absint($user['id']);
3666
- }
3667
-
3668
- $where_sql = '';
3669
- if ( $where ) {
3670
- $where_sql = ' WHERE ' . implode( ' AND ', $where );
3671
- }
3672
-
3673
- $order_sql = '';
3674
- if ( $order ) {
3675
- if ( ! empty( $order['DESC'] ) ) {
3676
- $order_sql = ' ORDER BY ' . preg_replace( '/[^\w]/', '', $order['DESC'] ) . ' DESC ';
3677
- }
3678
- elseif ( ! empty( $order['ASC'] ) ) {
3679
- $order_sql = ' ORDER BY ' . preg_replace( '/[^\w]/', '', $order['ASC'] ) . ' ASC ';
3680
- }
3681
- }
3682
-
3683
- $limit_sql = '';
3684
- if ( $limit ) {
3685
- $limit_sql = ' LIMIT ' . preg_replace( '/[^0-9\.]/', '', $limit );
3686
- }
3687
-
3688
- // $row = $wpdb->get_row('SELECT * FROM '.CERBER_LOG_TABLE.' WHERE activity = 5 AND user_id = '.absint($user_id) . ' ORDER BY stamp DESC LIMIT 1');
3689
- return $wpdb->get_results( 'SELECT * FROM ' . CERBER_LOG_TABLE . ' ' . $where_sql . $order_sql . $limit_sql );
3690
-
3691
- }
3692
-
3693
- /**
3694
- * Return the last login record for a given user
3695
- *
3696
- * @param $user_id int|null
3697
- * @param $user_email string
3698
- *
3699
- * @return array|null|object|string
3700
- */
3701
- function cerber_get_last_login( $user_id, $user_email = '' ) {
3702
- if ( $user_id ) {
3703
- $u = array( 'id' => $user_id );
3704
- }
3705
- elseif ( $user_email ) {
3706
- $u = array( 'email' => $user_email );
3707
- }
3708
-
3709
- if ($u) {
3710
- $recs = cerber_get_log( array( 5 ), $u, array( 'DESC' => 'stamp' ), 1 );
3711
- return $recs[0];
3712
- }
3713
-
3714
- return '';
3715
- }
3716
-
3717
- function cerber_count_log($activity = array(), $period = 1) {
3718
- global $wpdb;
3719
-
3720
- $period = absint( $period );
3721
- if ( ! $period ) {
3722
- $period = 1;
3723
- }
3724
-
3725
- $stamp = time() - $period * 24 * 3600;
3726
-
3727
- // TODO: replace with SELECT COUNT(DISTINCT session_id)
3728
- $ret = $wpdb->get_var('SELECT COUNT(ip) FROM '. CERBER_LOG_TABLE .' WHERE activity IN ('.implode(',',$activity).') AND stamp > '. $stamp);
3729
- if (!$ret) $ret = 0;
3730
-
3731
- return $ret;
3732
- }
3733
-
3734
- /**
3735
- * Create a set of parameters for using it in Subscriptions
3736
- * The keys are used to built an URL. Values to calculate a hash.
3737
- *
3738
- * @return array The set of parameters
3739
- */
3740
- function cerber_subscribe_params() {
3741
- $begin = 0;
3742
- $end = 0;
3743
- $ip = 0;
3744
- if ( ! empty( $_GET['filter_ip'] ) ) {
3745
- $ip = cerber_any2range( $_GET['filter_ip'] );
3746
- if ( is_array( $ip ) ) {
3747
- $begin = $ip['begin'];
3748
- $end = $ip['end'];
3749
- $ip = 0;
3750
- } elseif ( ! $ip ) {
3751
- $ip = 0;
3752
- }
3753
- }
3754
-
3755
- $filter_activity = ( empty( $_GET['filter_activity'] ) ) ? 0 : $_GET['filter_activity'];
3756
- $filter_user = ( empty( $_GET['filter_user'] ) ) ? 0 : $_GET['filter_user'];
3757
- $filter_login = ( empty( $_GET['filter_login'] ) ) ? 0 : $_GET['filter_login'];
3758
- $search_activity = ( empty( $_GET['search_activity'] ) ) ? 0 : $_GET['search_activity'];
3759
- $filter_role = ( empty( $_GET['filter_role'] ) ) ? 0 : $_GET['filter_role'];
3760
-
3761
- if ( ! is_array( $filter_activity ) ) {
3762
- $filter_activity = array( $filter_activity );
3763
- }
3764
- $filter_activity = array_filter( $filter_activity );
3765
-
3766
- // 'begin' and 'end' array keys are not used, added for compatibility
3767
- return array( 'filter_activity' => $filter_activity, 'filter_user' => $filter_user, 'being' => $begin, 'end' => $end, 'filter_ip' => $ip, 'filter_login' => $filter_login, 'search_activity' => $search_activity, 'filter_role' => $filter_role );
3768
- }
3769
-
3770
- /*
3771
- Plugin activation
3772
- */
3773
- register_activation_hook( __FILE__, 'cerber_activate' );
3774
- function cerber_activate() {
3775
- global $wp_version, $wp_cerber;
3776
- $assets_url = plugin_dir_url( CERBER_FILE ) . 'assets';
3777
-
3778
- //cerber_load_lang();
3779
- load_plugin_textdomain( 'wp-cerber', false, basename( dirname( __FILE__ ) ) . '/languages' );
3780
-
3781
- if ( version_compare( CERBER_REQ_PHP, phpversion(), '>' ) ) {
3782
- cerber_stop_activating( '<h3>' . sprintf( __( 'The WP Cerber requires PHP %s or higher. You are running', 'wp-cerber' ), CERBER_REQ_PHP ) . ' ' . phpversion() . '</h3>' );
3783
- }
3784
-
3785
- if ( version_compare( CERBER_REQ_WP, $wp_version, '>' ) ) {
3786
- cerber_stop_activating( '<h3>' . sprintf( __( 'The WP Cerber requires WordPress %s or higher. You are running', 'wp-cerber' ), CERBER_REQ_WP ) . ' ' . $wp_version . '</h3>' );
3787
- }
3788
-
3789
- $db_errors = cerber_create_db();
3790
- if ( $db_errors ) {
3791
- $e = '';
3792
- foreach ( $db_errors as $db_error ) {
3793
- $e .= '<p>' . implode( '</p><p>', $db_error ) . '</p>';
3794
- }
3795
- cerber_stop_activating( '<h3>' . __( "Can't activate WP Cerber due to a database error.", 'wp-cerber' ) . '</h3>'.$e);
3796
- }
3797
-
3798
- cerber_upgrade_all();
3799
-
3800
- cerber_cookie1();
3801
- cerber_disable_citadel();
3802
- //cerber_get_groove();
3803
-
3804
- if ( ! is_object( $wp_cerber ) ) {
3805
- $wp_cerber = new WP_Cerber();
3806
- }
3807
- cerber_add_white( cerber_get_subnet( $wp_cerber->getRemoteIp() ) ); // Protection for non-experienced user
3808
-
3809
- cerber_admin_message(
3810
- '<img style="float:left; margin-left:-10px;" src="' . $assets_url . '/icon-128x128.png">' .
3811
- '<p style="font-size:120%;">' . __( 'WP Cerber is now active and has started protecting your site', 'wp-cerber' ) . '</p>' .
3812
- ' <p>' . __( 'Your IP address is added to the', 'wp-cerber' ) . ' ' . __( 'White IP Access List', 'wp-cerber' ) .
3813
-
3814
- ' <p style="font-size:120%;"><a href="http://wpcerber.com/getting-started/" target="_blank">' . __( 'Getting Started Guide', 'wp-cerber' ) . '</a></p>' .
3815
-
3816
- //' <p><b>' . __( "It's important to check security settings.", 'wp-cerber' ) . '</b> &nbsp;<a href="http://wpcerber.com/" target="_blank">Read Cerber\'s blog</a> ' .
3817
- //'&nbsp; <a href="http://wpcerber.com/subscribe-newsletter/" target="_blank">Subscribe to Cerber\'s newsletter</a></p>' .
3818
-
3819
- ' <p> </p><p><span class="dashicons dashicons-admin-settings"></span> <a href="' . cerber_admin_link( 'main' ) . '">' . __( 'Main Settings', 'wp-cerber' ) . '</a>' .
3820
- ' <span style="margin-left:20px;" class="dashicons dashicons-admin-network"></span> <a href="' . cerber_admin_link( 'acl' ) . '">' . __( 'Access Lists', 'wp-cerber' ) . '</a>' .
3821
- ' <span style="margin-left:20px;" class="dashicons dashicons-forms"></span> <a href="' . cerber_admin_link( 'antispam' ) . '">' . __( 'Antispam', 'wp-cerber' ) . '</a>' .
3822
- ' <span style="margin-left:20px;" class="dashicons dashicons-shield-alt"></span> <a href="' . cerber_admin_link( 'hardening' ) . '">' . __( 'Hardening', 'wp-cerber' ) . '</a>' .
3823
- ' <span style="margin-left:20px;" class="dashicons dashicons-controls-volumeon"></span> <a href="' . cerber_admin_link( 'notifications' ) . '">' . __( 'Notifications', 'wp-cerber' ) . '</a>' .
3824
- ' <span style="margin-left:20px;" class="dashicons dashicons-admin-tools"></span> <a href="' . cerber_admin_link( 'imex' ) . '">' . __( 'Import settings', 'wp-cerber' ) . '</a>' .
3825
- '</p>' );
3826
-
3827
-
3828
- // Check for existing options
3829
- $opt = cerber_get_options();
3830
- $opt = array_filter( $opt );
3831
- if ( ! empty( $opt ) ) {
3832
- return;
3833
- }
3834
-
3835
- cerber_load_defaults();
3836
-
3837
- cerber_send_notify( 'activated' );
3838
-
3839
- $pi = get_file_data( cerber_plugin_file(), array( 'Version' => 'Version' ), 'plugin' );
3840
- $pi ['time'] = time();
3841
- $pi ['user'] = get_current_user_id();
3842
- update_site_option( '_cerber_activated', $pi );
3843
- }
3844
-
3845
- /*
3846
- Abort activating plugin!
3847
- */
3848
- function cerber_stop_activating( $msg ) {
3849
- deactivate_plugins( plugin_basename( __FILE__ ) );
3850
- wp_die( $msg );
3851
- }
3852
-
3853
- /**
3854
- * Upgrade database tables, data and plugin settings
3855
- *
3856
- * @since 3.0
3857
- *
3858
- */
3859
- function cerber_upgrade_all() {
3860
- $ver = cerber_get_site_option( '_cerber_up' );
3861
- if ( ! $ver || $ver['v'] != CERBER_VER ) {
3862
- cerber_create_db();
3863
- cerber_upgrade_db();
3864
- cerber_acl_fixer( true );
3865
- cerber_push_the_news( CERBER_VER );
3866
- cerber_antibot_gene(true);
3867
- cerber_upgrade_options();
3868
- wp_clear_scheduled_hook( 'cerber_hourly' ); // @since 5.8
3869
- update_site_option( '_cerber_up', array( 'v' => CERBER_VER, 't' => time() ) );
3870
- }
3871
- }
3872
-
3873
- /**
3874
- * Creates DB tables if they don't exist
3875
- *
3876
- * @param bool $recreate If true, recreate some tables completely (with data lost)
3877
- *
3878
- * @return array Errors
3879
- */
3880
- function cerber_create_db($recreate = true) {
3881
- global $wpdb;
3882
-
3883
- $wpdb->hide_errors();
3884
- $db_errors = array();
3885
- $sql = array();
3886
-
3887
- if (!cerber_is_table(CERBER_LOG_TABLE)){
3888
- $sql[] = "
3889
- CREATE TABLE IF NOT EXISTS " . CERBER_LOG_TABLE . " (
3890
- ip varchar(39) CHARACTER SET ascii NOT NULL COMMENT 'Remote IP',
3891
- user_login varchar(60) NOT NULL COMMENT 'Username from HTTP request',
3892
- user_id bigint(20) unsigned NOT NULL DEFAULT '0',
3893
- stamp bigint(20) unsigned NOT NULL COMMENT 'Unix timestamp',
3894
- activity int(10) unsigned NOT NULL DEFAULT '0',
3895
- KEY ip (ip)
3896
- ) DEFAULT CHARSET=utf8 COMMENT='Cerber activity log';
3897
- ";
3898
- }
3899
-
3900
- if (!cerber_is_table(CERBER_ACL_TABLE)){
3901
- $sql[] = "
3902
- CREATE TABLE IF NOT EXISTS " . CERBER_ACL_TABLE . " (
3903
- ip varchar(39) CHARACTER SET ascii NOT NULL COMMENT 'IP',
3904
- tag char(1) NOT NULL COMMENT 'Type: B or W',
3905
- comments varchar(250) NOT NULL,
3906
- UNIQUE KEY ip (ip)
3907
- ) DEFAULT CHARSET=utf8 COMMENT='Cerber IP Access Lists';
3908
- ";
3909
- }
3910
-
3911
- if (!cerber_is_table(CERBER_BLOCKS_TABLE)){
3912
- $sql[] = "
3913
- CREATE TABLE IF NOT EXISTS " . CERBER_BLOCKS_TABLE . " (
3914
- ip varchar(39) CHARACTER SET ascii NOT NULL COMMENT 'Remote IP',
3915
- block_until bigint(20) unsigned NOT NULL COMMENT 'Unix timestamp',
3916
- reason varchar(250) NOT NULL COMMENT 'Why IP was blocked',
3917
- UNIQUE KEY ip (ip)
3918
- ) DEFAULT CHARSET=utf8 COMMENT='Cerber list of currently blocked IPs';
3919
- ";
3920
- }
3921
-
3922
- if (!cerber_is_table(CERBER_LAB_TABLE)){
3923
- $sql[] = "
3924
- CREATE TABLE IF NOT EXISTS " . CERBER_LAB_TABLE . " (
3925
- ip varchar(39) CHARACTER SET ascii NOT NULL COMMENT 'Remote IP',
3926
- reason_id int(11) unsigned NOT NULL DEFAULT '0',
3927
- stamp bigint(20) unsigned NOT NULL COMMENT 'Unix timestamp',
3928
- details text NOT NULL
3929
- ) DEFAULT CHARSET=utf8 COMMENT='Cerber lab cache';
3930
- ";
3931
- }
3932
-
3933
-
3934
- if ($recreate || !cerber_is_table(CERBER_LAB_IP_TABLE)){
3935
- if ( $recreate && cerber_is_table( CERBER_LAB_IP_TABLE ) ) {
3936
- $sql[] = 'DROP TABLE IF EXISTS ' . CERBER_LAB_IP_TABLE;
3937
- }
3938
- $sql[] = "
3939
- CREATE TABLE IF NOT EXISTS " . CERBER_LAB_IP_TABLE . " (
3940
- ip varchar(39) CHARACTER SET ascii NOT NULL COMMENT 'IP',
3941
- reputation INT(11) UNSIGNED NOT NULL COMMENT 'Reputation of IP',
3942
- expires INT(11) UNSIGNED NOT NULL COMMENT 'Unix timestamp',
3943
- PRIMARY KEY (ip)
3944
- ) DEFAULT CHARSET=utf8 COMMENT='Cerber lab IP cache';
3945
- ";
3946
- }
3947
-
3948
- if ( $recreate || ! cerber_is_table( CERBER_LAB_NET_TABLE ) ) {
3949
- if ( $recreate && cerber_is_table( CERBER_LAB_NET_TABLE ) ) {
3950
- $sql[] = 'DROP TABLE IF EXISTS ' . CERBER_LAB_NET_TABLE;
3951
- }
3952
- $sql[] = '
3953
- CREATE TABLE IF NOT EXISTS ' . CERBER_LAB_NET_TABLE . ' (
3954
- ip varchar(39) CHARACTER SET ascii NOT NULL DEFAULT "" COMMENT "IP address",
3955
- ip_long_begin BIGINT UNSIGNED NOT NULL DEFAULT "0",
3956
- ip_long_end BIGINT UNSIGNED NOT NULL DEFAULT "0",
3957
- country CHAR(3) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL DEFAULT "" COMMENT "Country code",
3958
- expires INT(11) UNSIGNED NOT NULL DEFAULT "0",
3959
- PRIMARY KEY (ip),
3960
- UNIQUE KEY begin_end (ip_long_begin, ip_long_end)
3961
- ) DEFAULT CHARSET=utf8 COMMENT="Cerber lab network cache";
3962
- ';
3963
- }
3964
-
3965
- if (!cerber_is_table(CERBER_GEO_TABLE)){
3966
- $sql[] = '
3967
- CREATE TABLE IF NOT EXISTS ' . CERBER_GEO_TABLE . ' (
3968
- country CHAR(3) NOT NULL DEFAULT "" COMMENT "Country code",
3969
- locale CHAR(10) NOT NULL DEFAULT "" COMMENT "Locale i18n",
3970
- country_name VARCHAR(250) NOT NULL DEFAULT "" COMMENT "Country name",
3971
- PRIMARY KEY (country, locale)
3972
- ) DEFAULT CHARSET=utf8;
3973
- ';
3974
- }
3975
-
3976
- if (!cerber_is_table(CERBER_TRAF_TABLE)){
3977
- $sql[] = '
3978
- CREATE TABLE IF NOT EXISTS ' . CERBER_TRAF_TABLE . ' (
3979
- ip varchar(39) CHARACTER SET ascii NOT NULL,
3980
- ip_long BIGINT UNSIGNED NOT NULL DEFAULT "0",
3981
- hostname varchar(250) NOT NULL DEFAULT "",
3982
- uri text NOT NULL,
3983
- request_fields MEDIUMTEXT NOT NULL,
3984
- request_details MEDIUMTEXT NOT NULL,
3985
- session_id char(32) CHARACTER SET ascii NOT NULL,
3986
- user_id bigint(20) UNSIGNED NOT NULL DEFAULT 0,
3987
- stamp decimal(14,4) NOT NULL,
3988
- processing int(10) NOT NULL DEFAULT 0,
3989
- country char(3) CHARACTER SET ascii NOT NULL DEFAULT "",
3990
- request_method char(8) CHARACTER SET ascii NOT NULL,
3991
- http_code int(10) UNSIGNED NOT NULL,
3992
- wp_id bigint(20) UNSIGNED NOT NULL DEFAULT 0,
3993
- wp_type int(10) UNSIGNED NOT NULL DEFAULT 0,
3994
- is_bot int(10) UNSIGNED NOT NULL DEFAULT 0,
3995
- blog_id int(10) UNSIGNED NOT NULL DEFAULT 0,
3996
- KEY stamp (stamp)
3997
- ) DEFAULT CHARSET=utf8;
3998
- ';
3999
- }
4000
-
4001
- foreach ( $sql as $query ) {
4002
- if ( ! $wpdb->query( $query ) && $wpdb->last_error ) {
4003
- $db_errors[] = array( $wpdb->last_error, $wpdb->last_query );
4004
- }
4005
- }
4006
-
4007
- return $db_errors;
4008
- }
4009
-
4010
- /**
4011
- * Upgrade structure of existing DB tables
4012
- *
4013
- * @return array Errors during upgrading
4014
- * @since 3.0
4015
- */
4016
- function cerber_upgrade_db( $force = false ) {
4017
- global $wpdb;
4018
- $wpdb->hide_errors();
4019
- if ($force) $wpdb->suppress_errors();
4020
- $db_errors = array();
4021
- $sql = array();
4022
-
4023
- // @since 3.0
4024
- $sql[] = 'ALTER TABLE ' . CERBER_LOG_TABLE . ' CHANGE stamp stamp DECIMAL(14,4) NOT NULL';
4025
-
4026
- // @since 3.1
4027
- if ( $force || ! cerber_is_column( CERBER_LOG_TABLE, 'ip_long' ) ) {
4028
- $sql[] = 'ALTER TABLE ' . CERBER_LOG_TABLE . ' ADD ip_long BIGINT UNSIGNED NOT NULL DEFAULT "0" COMMENT "IPv4 long" AFTER ip, ADD INDEX (ip_long)';
4029
- }
4030
- if ( $force || ! cerber_is_column( CERBER_ACL_TABLE, 'ip_long_begin' ) ) {
4031
- $sql[] = 'ALTER TABLE ' . CERBER_ACL_TABLE . " ADD ip_long_begin BIGINT UNSIGNED NOT NULL DEFAULT '0' COMMENT 'IPv4 range begin' AFTER ip, ADD ip_long_end BIGINT UNSIGNED NOT NULL DEFAULT '0' COMMENT 'IPv4 range end' AFTER ip_long_begin";
4032
- }
4033
- if ( $force || !cerber_is_index( CERBER_ACL_TABLE, 'ip_begin_end' ) ) {
4034
- $sql[] = 'ALTER TABLE ' . CERBER_ACL_TABLE . ' ADD UNIQUE ip_begin_end (ip, ip_long_begin, ip_long_end)';
4035
- }
4036
- if ( $force || cerber_is_index( CERBER_ACL_TABLE, 'ip' ) ) {
4037
- $sql[] = 'ALTER TABLE ' . CERBER_ACL_TABLE . ' DROP INDEX ip';
4038
- }
4039
-
4040
- // @since 4.8.2
4041
- if ( $force || cerber_is_index( CERBER_ACL_TABLE, 'begin_end' ) ) {
4042
- $sql[] = 'ALTER TABLE ' . CERBER_ACL_TABLE . ' DROP INDEX begin_end';
4043
- }
4044
- if ( $force || !cerber_is_index( CERBER_ACL_TABLE, 'begin_end_tag' ) ) {
4045
- $sql[] = 'ALTER TABLE ' . CERBER_ACL_TABLE . ' ADD INDEX begin_end_tag (ip_long_begin, ip_long_end, tag)';
4046
- }
4047
-
4048
- // @since 4.9
4049
- if ( $force || ! cerber_is_column( CERBER_LOG_TABLE, 'session_id' ) ) {
4050
- $sql[] = 'ALTER TABLE ' . CERBER_LOG_TABLE . '
4051
- ADD session_id CHAR(32) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL DEFAULT "",
4052
- ADD country CHAR(3) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL DEFAULT "" COMMENT "Country code",
4053
- ADD details VARCHAR(250) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL DEFAULT "" COMMENT "Details about HTTP request";
4054
- ';
4055
- }
4056
-
4057
- // @since 6.1
4058
- if ( $force || !cerber_is_index( CERBER_LOG_TABLE, 'session_index' ) ) {
4059
- $sql[] = 'ALTER TABLE ' . CERBER_LOG_TABLE . ' ADD INDEX session_index (session_id)';
4060
- }
4061
-
4062
- if (!empty($sql)) {
4063
- foreach ( $sql as $query ) {
4064
- if ( !$wpdb->query( $query ) && $wpdb->last_error ) {
4065
- $db_errors[] = array( $wpdb->last_error, $wpdb->last_query );
4066
- }
4067
- }
4068
- }
4069
-
4070
- // Convert existing data into the new format
4071
-
4072
- cerber_acl_fixer();
4073
-
4074
- if ( $db_errors ) {
4075
- update_site_option( '_cerber_db_errors', $db_errors );
4076
- }
4077
- else {
4078
- update_site_option( '_cerber_db_errors', '' );
4079
- }
4080
-
4081
- return $db_errors;
4082
- }
4083
-
4084
- /**
4085
- * Updating old activity log records to the new row format (has been introduced in v 3.1)
4086
- *
4087
- * @since 4.0
4088
- *
4089
- */
4090
- function cerber_up_data() {
4091
- global $wpdb;
4092
- $ips = $wpdb->get_col( 'SELECT DISTINCT ip FROM ' . CERBER_LOG_TABLE . ' WHERE ip_long = 0 LIMIT 50' );
4093
- if ( ! $ips ) {
4094
- return;
4095
- }
4096
- foreach ( $ips as $ip ) {
4097
- if ( cerber_is_ipv4( $ip ) ) {
4098
- $ip_long = ip2long( $ip );
4099
- } else {
4100
- $ip_long = 1;
4101
- }
4102
- $wpdb->query( 'UPDATE ' . CERBER_LOG_TABLE . ' SET ip_long = ' . $ip_long . ' WHERE ip = "' . $ip .'" AND ip_long = 0');
4103
- }
4104
- }
4105
-
4106
- /**
4107
- * Upgrade corrupted / from older versions of the plugin rows in ACL
4108
- *
4109
- * @param bool $ipv6 if true Process IPv6 addresses
4110
- *
4111
- */
4112
- function cerber_acl_fixer($ipv6 = false){
4113
- global $wpdb;
4114
-
4115
- // Repair/update IPs without long values
4116
- $rows = $wpdb->get_col( 'SELECT ip FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin = 0 OR ip_long_end = 0' );
4117
- if ( ! $rows ) {
4118
- return;
4119
- }
4120
- foreach ( $rows as $ip ) {
4121
- if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) ) {
4122
- continue;
4123
- }
4124
- $range = cerber_any2range( $ip );
4125
- if ( is_array( $range ) ) {
4126
- $begin = $range['begin'];
4127
- $end = $range['end'];
4128
- }
4129
- else {
4130
- $begin = ip2long( $ip );
4131
- $end = ip2long( $ip );
4132
- }
4133
-
4134
- $wpdb->query( 'UPDATE ' . CERBER_ACL_TABLE . ' SET ip_long_begin = ' . $begin . ', ip_long_end = ' . $end . ' WHERE ip = "' . $ip .'"');
4135
- }
4136
-
4137
- // Convert old IPv6 to all shortened
4138
- if ( $ipv6 ) {
4139
- $ips = $wpdb->get_col( 'SELECT ip FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin = 0' );
4140
- if ( $ips ) {
4141
- foreach ( $ips as $ip ) {
4142
- if ( ! filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) ) {
4143
- continue;
4144
- }
4145
- $short_ip = cerber_short_ipv6( $ip );
4146
- if ($short_ip != $ip) {
4147
- $wpdb->query( 'UPDATE ' . CERBER_ACL_TABLE . ' SET ip = "' . $short_ip . '" WHERE ip = "' . $ip . '"' );
4148
- }
4149
- }
4150
- }
4151
- }
4152
- }
4153
-
4154
- $file = plugin_basename( cerber_plugin_file() );
4155
- add_action( 'deac' . 'tivate_' . $file, 'cerber_clean' );
4156
- function cerber_clean( $ip ) {
4157
- wp_clear_scheduled_hook( 'cerber' . '_hourly' );
4158
- $pi = get_file_data( cerber_plugin_file(), array( 'Version' => 'Version' ), 'plugin' );
4159
- $pi ['v'] = time();
4160
- $pi ['u'] = get_current_user_id();
4161
- update_site_option( '_cerber_o' . 'ff', $pi );
4162
- $f = 'cerb' . 'er_se' . 'nd_not' . 'ify';
4163
- $f( 'sh' . 'utd' . 'own' );
4164
- }
4165
-
4166
- /*
4167
- Fix an issue with the empty user_id field in the comments table.
4168
- */
4169
- add_filter( 'preprocess_comment', 'cerber_add_uid' );
4170
- function cerber_add_uid( $commentdata ) {
4171
- $current_user = wp_get_current_user();
4172
- $commentdata['user_ID'] = $current_user->ID;
4173
-
4174
- return $commentdata;
4175
- }
4176
-
4177
- /**
4178
- * Load jQuery on the page
4179
- *
4180
- */
4181
- add_action( 'login_enqueue_scripts', 'cerber_login_scripts' );
4182
- function cerber_login_scripts() {
4183
- if ( cerber_antibot_enabled( array('botsreg', 'botsany') ) ) {
4184
- wp_enqueue_script( 'jquery' );
4185
- }
4186
- }
4187
- add_action( 'wp_enqueue_scripts', 'cerber_scripts' );
4188
- function cerber_scripts() {
4189
- global $wp_cerber;
4190
- if ( ( is_singular() && cerber_antibot_enabled( array( 'botscomm', 'botsany' ) ) )
4191
- || ( $wp_cerber->getSettings( 'sitekey' ) && $wp_cerber->getSettings( 'secretkey' ) )
4192
- ) {
4193
- wp_enqueue_script( 'jquery' );
4194
- }
4195
- }
4196
-
4197
- /**
4198
- * Footer stuff
4199
- * Explicit rendering reCAPTCHA
4200
- *
4201
- */
4202
- add_action( 'login_footer', 'cerber_login_foo', 1000 );
4203
- function cerber_login_foo( $ip ) {
4204
- global $wp_cerber;
4205
-
4206
- cerber_antibot_code(array( 'botsreg', 'botsany' ));
4207
-
4208
- // Universal JS
4209
- if (!$wp_cerber->recaptcha_here) return;
4210
-
4211
- $sitekey = $wp_cerber->getSettings('sitekey');
4212
-
4213
- if (!$wp_cerber->getSettings('invirecap')){
4214
- // Classic version (visible reCAPTCHA)
4215
- echo '<script src = https://www.google.com/recaptcha/api.js?hl='.cerber_recaptcha_lang().' async defer></script>';
4216
- }
4217
- else {
4218
- // Pure JS version with explicit rendering
4219
- ?>
4220
- <script src="https://www.google.com/recaptcha/api.js?onload=init_recaptcha_widgets&render=explicit&hl=<?php echo cerber_recaptcha_lang(); ?>" async defer></script>
4221
- <script type='text/javascript'>
4222
-
4223
- document.getElementById("cerber-recaptcha").remove();
4224
-
4225
- var init_recaptcha_widgets = function () {
4226
- for (var i = 0; i < document.forms.length; ++i) {
4227
- var form = document.forms[i];
4228
- var place = form.querySelector('.cerber-form-marker');
4229
- if (null !== place) render_recaptcha_widget(form, place);
4230
- }
4231
- };
4232
-
4233
- function render_recaptcha_widget(form, place) {
4234
- var place_id = grecaptcha.render(place, {
4235
- 'callback': function (g_recaptcha_response) {
4236
- HTMLFormElement.prototype.submit.call(form);
4237
- },
4238
- 'sitekey': '<?php echo $sitekey; ?>',
4239
- 'size': 'invisible',
4240
- 'badge': 'bottomright'
4241
- });
4242
-
4243
- form.onsubmit = function (event) {
4244
- event.preventDefault();
4245
- grecaptcha.execute(place_id);
4246
- };
4247
-
4248
- }
4249
- </script>
4250
- <?php
4251
- }
4252
- }
4253
-
4254
- /**
4255
- * Inline reCAPTCHA widget
4256
- *
4257
- */
4258
- add_action( 'wp_footer', 'cerber_foo', 1000 );
4259
- function cerber_foo() {
4260
- global $wp_cerber;
4261
-
4262
- if (is_singular()) cerber_antibot_code( array( 'botscomm', 'botsany' ) );
4263
-
4264
- if (!$wp_cerber->recaptcha_here) return;
4265
-
4266
- // jQuery version with support visible and invisible reCAPTCHA
4267
- // TODO: convert it into pure JS
4268
- ?>
4269
- <script type="text/javascript">
4270
-
4271
- jQuery(document).ready(function ($) {
4272
-
4273
- var recaptcha_ok = false;
4274
- var the_recaptcha_widget = $("#cerber-recaptcha");
4275
- var is_recaptcha_visible = ($(the_recaptcha_widget).data('size') !== 'invisible');
4276
-
4277
- var the_form = $(the_recaptcha_widget).closest("form");
4278
- var the_button = $(the_form).find('input[type="submit"]');
4279
- if (!the_button.length) {
4280
- the_button = $(the_form).find(':button');
4281
- }
4282
-
4283
- // visible
4284
- if (the_button.length && is_recaptcha_visible) {
4285
- the_button.prop("disabled", true);
4286
- the_button.css("opacity", 0.5);
4287
- }
4288
-
4289
- window.form_button_enabler = function () {
4290
- if (!the_button.length) return;
4291
- the_button.prop("disabled", false);
4292
- the_button.css( "opacity", 1 );
4293
- };
4294
-
4295
- // invisible
4296
- if (!is_recaptcha_visible) {
4297
- $(the_button).click(function (event) {
4298
- if (recaptcha_ok) return;
4299
- event.preventDefault();
4300
- grecaptcha.execute();
4301
- });
4302
- }
4303
-
4304
- window.now_submit_the_form = function () {
4305
- recaptcha_ok = true;
4306
- $(the_button).click(); // this is only way to submit a form that contains "submit" inputs
4307
- };
4308
- });
4309
- </script>
4310
- <script src = "https://www.google.com/recaptcha/api.js?hl=<?php echo cerber_recaptcha_lang(); ?>" async defer></script>
4311
- <?php
4312
- }
4313
-
4314
-
4315
- // Traffic Logging ======================================================================
4316
-
4317
- //add_action( 'wp', 'cerber_traffic_log' );
4318
- add_action( 'shutdown', function () {
4319
- cerber_traffic_log();
4320
- } );
4321
- register_shutdown_function( 'cerber_traffic_log' );
4322
- /**
4323
- * Traffic Logging
4324
- *
4325
- * @since 6.0
4326
- */
4327
- function cerber_traffic_log(){
4328
- global $wpdb, $wp_query, $wp_cerber_user_id, $wp_cerber_start_stamp, $blog_id;
4329
- static $logged = false;
4330
-
4331
- if ( $logged ) {
4332
- return;
4333
- }
4334
-
4335
- $wp_cerber = get_wp_cerber();
4336
-
4337
- $wp_type = 700;
4338
-
4339
- if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
4340
- /*
4341
- if ( isset( $_POST['action'] ) && $_POST['action'] == 'heartbeat' ) {
4342
- return;
4343
- }*/
4344
- $wp_type = 500;
4345
- }
4346
- elseif ( is_admin() ) {
4347
- $wp_type = 501;
4348
- }
4349
- elseif ( defined( 'DOING_CRON' ) && DOING_CRON ) {
4350
- $wp_type = 502;
4351
- }
4352
- elseif ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
4353
- $wp_type = 515;
4354
- }
4355
- elseif ( cerber_is_rest_url() ) {
4356
- $wp_type = 520;
4357
- }
4358
- // Public part starts with 600
4359
- elseif ( $wp_query && is_object( $wp_query ) ) {
4360
- $wp_type = 600;
4361
- if ( $wp_query->is_singular ) {
4362
- $wp_type = 601;
4363
- }
4364
- elseif ( $wp_query->is_tag ) {
4365
- $wp_type = 603;
4366
- }
4367
- elseif ( $wp_query->is_category ) {
4368
- $wp_type = 604;
4369
- }
4370
- elseif ( $wp_query->is_search ) {
4371
- $wp_type = 605;
4372
- }
4373
- }
4374
-
4375
- if ( function_exists( 'http_response_code' ) ) { // PHP >= 5.4.0, PHP 7
4376
- $http_code = http_response_code();
4377
- }
4378
- else {
4379
- //get_status_header_desc()
4380
- // TODO: Add detection for other HTTP codes for PHP 5.3
4381
- $http_code = 200;
4382
- if ( $wp_type > 600 ) {
4383
- if ( $wp_query->is_404 ) {
4384
- $http_code = 404;
4385
- }
4386
- }
4387
- }
4388
-
4389
- $user_id = 0;
4390
- if ( function_exists( 'get_current_user_id' ) ) {
4391
- $user_id = get_current_user_id();
4392
- }
4393
- if ( ! $user_id && $wp_cerber_user_id ) {
4394
- $user_id = absint( $wp_cerber_user_id );
4395
- }
4396
-
4397
- if ( ! cerber_to_log( $wp_type, $http_code, $user_id ) ) {
4398
- return;
4399
- }
4400
-
4401
- $logged = true;
4402
-
4403
- $ua = '';
4404
- if ( ! empty( $_SERVER['HTTP_USER_AGENT'] ) ) {
4405
- $ua = substr ($_SERVER['HTTP_USER_AGENT'], 0, 1000);
4406
- }
4407
-
4408
- $bot = cerber_is_crawler( $ua );
4409
- if ( $bot && crb_get_settings( 'tinocrabs' ) ) {
4410
- return;
4411
- }
4412
-
4413
- $ip = $wp_cerber->getRemoteIp();
4414
- $ip_long = 0;
4415
- if ( cerber_is_ipv4( $ip ) ) {
4416
- $ip_long = ip2long( $ip );
4417
- }
4418
-
4419
- $wp_id = 0;
4420
- if ( $wp_query && is_object( $wp_query ) ) {
4421
- $wp_id = absint( $wp_query->get_queried_object_id() );
4422
- }
4423
-
4424
- $session_id = $wp_cerber->getSessionID();
4425
- if ( is_ssl() ) {
4426
- $scheme = 'https';
4427
- }
4428
- else {
4429
- $scheme = 'http';
4430
- }
4431
- $uri = $scheme . '://'. $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
4432
- $method = preg_replace( '/[^\w]/', '', $_SERVER['REQUEST_METHOD'] );
4433
-
4434
- // Request fields
4435
-
4436
- $fields = '';
4437
- if ( crb_get_settings( 'tifields' ) ) {
4438
- $fields = array();
4439
- if ( ! empty( $_POST ) ) {
4440
- $fields[1] = cerber_prepare_fields( cerber_mask_fields( (array) $_POST ) );
4441
- }
4442
- if ( ! empty( $_GET ) ) {
4443
- $fields[2] = cerber_prepare_fields( (array) $_GET );
4444
- }
4445
- if ( ! empty( $_FILES ) ) {
4446
- $fields[3] = $_FILES;
4447
- }
4448
- if ( ! empty( $fields ) ) {
4449
- $fields = serialize( $fields );
4450
- }
4451
- else {
4452
- $fields = '';
4453
- }
4454
- }
4455
-
4456
- // Extra request details
4457
-
4458
- $details = array();
4459
- if ( $ua ) {
4460
- $details[1] = $ua;
4461
- }
4462
- if ( ! empty( $_SERVER['HTTP_REFERER'] ) ) {
4463
- //$ref = mb_substr( $_SERVER['HTTP_REFERER'], 0, 1048576 ); // 1 Mb for ASCII
4464
- $details[2] = filter_var( $_SERVER['HTTP_REFERER'], FILTER_SANITIZE_URL );
4465
- }
4466
- /*
4467
- if ( ! empty( $_FILES ) ) {
4468
- $details[3] = $_FILES;
4469
- }*/
4470
- if ( $wp_type == 605 && ! empty( $_GET['s'] ) ) {
4471
- $details[4] = $_GET['s'];
4472
- }
4473
- if ( $wp_type == 515 ) {
4474
- // TODO: add a setting to enable it because there is a user/password in the php://input
4475
- //$details[5] = file_get_contents('php://input');
4476
- }
4477
- if ( crb_get_settings( 'tihdrs' ) ) {
4478
- $hds = getallheaders();
4479
- unset( $hds['Cookie'] );
4480
- $details[6] = $hds;
4481
- }
4482
- if ( crb_get_settings( 'tisenv' ) ) {
4483
- $srv = $_SERVER;
4484
- unset( $srv['HTTP_COOKIE'] );
4485
- $details[7] = $srv;
4486
- }
4487
- if ( crb_get_settings( 'ticandy' ) && ! empty( $_COOKIE ) ) {
4488
- $details[8] = $_COOKIE;
4489
- }
4490
- if ( !empty( $details ) ) {
4491
- /*
4492
- foreach ( $details as &$detail ) {
4493
- $detail = mb_substr($detail, 0, 1048576); // 1 Mb for ASCII
4494
- }*/
4495
- $details = cerber_prepare_fields( $details );
4496
- $details = serialize($details);
4497
- }
4498
- else {
4499
- $details = '';
4500
- }
4501
-
4502
- // Timestamps
4503
- if ( ! empty( $wp_cerber_start_stamp ) && is_numeric( $wp_cerber_start_stamp ) ) {
4504
- $stamp = (float)$wp_cerber_start_stamp; // define this variable: $wp_cerber_start_stamp = microtime( true ); in wp-config.php
4505
- }
4506
- else {
4507
- $stamp = cerber_request_time();
4508
- }
4509
-
4510
- $processing = (int) ( 1000 * ( microtime( true ) - $stamp ) );
4511
-
4512
- $uri = cerber_real_escape($uri);
4513
- $fields = cerber_real_escape($fields);
4514
- $details = cerber_real_escape($details);
4515
-
4516
- //$uri = $wpdb->remove_placeholder_escape( esc_sql( $uri ) );
4517
- //$fields = $wpdb->remove_placeholder_escape( esc_sql( $fields ) );
4518
- //$details = $wpdb->remove_placeholder_escape( esc_sql( $details ) );
4519
-
4520
- //$query = $wpdb->prepare( 'INSERT INTO ' . CERBER_TRAF_TABLE . ' (ip, ip_long, uri, request_fields , request_details, session_id, user_id, stamp, processing, request_method, http_code, wp_id, wp_type, is_bot, blog_id ) VALUES ("' .$ip .'", '. $ip_long . ', %s, %s, %s, "' . $session_id . '", ' . $user_id . ', ' . $stamp . ',' . $processing . ', "' . $method . '", ' . $http_code . ',' . $wp_id . ', ' . $wp_type . ', ' . $bot . ', ' . absint($blog_id) . ')', $uri, $fields, $details);
4521
-
4522
- $query = 'INSERT INTO ' . CERBER_TRAF_TABLE . ' (ip, ip_long, uri, request_fields , request_details, session_id, user_id, stamp, processing, request_method, http_code, wp_id, wp_type, is_bot, blog_id ) VALUES ("' . $ip . '", ' . $ip_long . ',"' . $uri . '","' . $fields . '","' . $details . '", "' . $session_id . '", ' . $user_id . ', ' . $stamp . ',' . $processing . ', "' . $method . '", ' . $http_code . ',' . $wp_id . ', ' . $wp_type . ', ' . $bot . ', ' . absint( $blog_id ) . ')';
4523
-
4524
- //$ret = $wpdb->query( $query );
4525
-
4526
- $ret = cerber_direct_db_query( $query );
4527
-
4528
- if (!$ret){
4529
-
4530
- // mysqli_error($wpdb->dbh);
4531
-
4532
- // TODO: Daily software error report
4533
- /*
4534
- echo mysqli_sqlstate($wpdb->dbh);
4535
- echo $wpdb->last_error;
4536
- echo "<p>\n";
4537
- echo $uri;
4538
- echo "<p>\n";
4539
- echo '<p>ERR '.$query.$wpdb->last_error;
4540
- echo '<p>'.$wpdb->_real_escape( $uri );
4541
- */
4542
- }
4543
-
4544
- }
4545
-
4546
- /**
4547
- * To log or not to log current request?
4548
- *
4549
- * @param $wp_type integer
4550
- * @param $http_code integer
4551
- * @param $user_id integer
4552
- *
4553
- * @return bool
4554
- * @since 6.0
4555
- */
4556
- function cerber_to_log($wp_type = 0, $http_code, $user_id){
4557
- global $cerber_logged;
4558
-
4559
- $mode = crb_get_settings( 'timode' );
4560
-
4561
- if ($mode == 0) {
4562
- return false;
4563
- }
4564
- if ($mode == 2) {
4565
- if ($wp_type < 515) { // Pure admin requests
4566
- return false;
4567
- }
4568
- return true;
4569
- }
4570
-
4571
- // Smart mode ---------------------------------------------------------
4572
-
4573
- if ( ! empty( $cerber_logged ) ) {
4574
- $tmp = $cerber_logged;
4575
- unset( $tmp[7] );
4576
- unset( $tmp[51] );
4577
- if ( ! empty( $tmp ) ) {
4578
- return true;
4579
- }
4580
- }
4581
-
4582
- if ($wp_type < 515) {
4583
- return false;
4584
- }
4585
-
4586
- if ( $http_code >= 400 ||
4587
- $wp_type < 600 ||
4588
- $user_id ||
4589
- cerber_is_http_post() ||
4590
- isset($_GET['s']) ||
4591
- cerber_get_non_wp_fields()){
4592
- return true;
4593
- }
4594
-
4595
- if ( cerber_get_uri_script() ) {
4596
- return true;
4597
- }
4598
-
4599
- return false;
4600
- }
4601
-
4602
- /**
4603
- * Mask sensitive request fields before saving in DB (avoid information leaks)
4604
- *
4605
- * @param $fields array
4606
- *
4607
- * @return array
4608
- * @since 6.0
4609
- */
4610
- function cerber_mask_fields( $fields ) {
4611
- $to_mask = array( 'pwd', 'pass', 'password' );
4612
- if ($list = (array)crb_get_settings( 'timask' )){
4613
- $to_mask = array_merge($to_mask, $list);
4614
- }
4615
- foreach ( $to_mask as $mask_field ) {
4616
- if ( ! empty( $fields[ $mask_field ] ) ) {
4617
- $fields[ $mask_field ] = str_pad( '', mb_strlen( $fields[ $mask_field ] ), '*' );
4618
- }
4619
- }
4620
-
4621
- return $fields;
4622
- }
4623
-
4624
- /**
4625
- * Recursive prepare values in array for inserting into DB
4626
- *
4627
- * @param $list
4628
- *
4629
- * @return mixed
4630
- * @since 6.0
4631
- */
4632
- function cerber_prepare_fields( $list ) {
4633
- foreach ( $list as &$field ) {
4634
- if ( is_array( $field ) ) {
4635
- cerber_prepare_fields( @$field );
4636
- /*
4637
- foreach ( $field as &$field_2 ) {
4638
- $field_2 = mb_substr( $field_2, 0, 1048576 ); // 1 Mb for ASCII
4639
- }*/
4640
- }
4641
- else {
4642
- if ( ! $field ) {
4643
- $field = '';
4644
- }
4645
- $field = mb_substr( $field, 0, 1048576 ); // 1 Mb for ASCII
4646
- }
4647
- }
4648
-
4649
- $list = stripslashes_deep( $list );
4650
-
4651
- return $list;
4652
- }
4653
-
4654
- /**
4655
- * Request time
4656
- *
4657
- * @return mixed
4658
- * @since 6.0
4659
- */
4660
- function cerber_request_time() {
4661
- static $stamp;
4662
-
4663
- if ( ! isset( $stamp ) ) {
4664
- if ( ! empty( $_SERVER['REQUEST_TIME_FLOAT'] ) ) { // PHP >= 5.4
4665
- $stamp = $_SERVER['REQUEST_TIME_FLOAT'];
4666
- }
4667
- else {
4668
- $stamp = microtime( true );
4669
- }
4670
- }
4671
-
4672
- return $stamp;
4673
- }
4674
-
4675
- /**
4676
- * Return non WP public query fields
4677
- *
4678
- * @param array $fields An associative array field => value to check
4679
- *
4680
- * @return array
4681
- * @since 6.0
4682
- */
4683
- function cerber_get_non_wp_fields($fields = array()) {
4684
- global $wp_query;
4685
-
4686
- if ( empty( $fields ) ) {
4687
- $get_keys = array_keys( $_GET );
4688
- }
4689
- else {
4690
- $get_keys = array_keys( $fields );
4691
- }
4692
-
4693
- if ( empty( $get_keys ) ) {
4694
- return array();
4695
- }
4696
-
4697
- if ( is_object($wp_query) ) {
4698
- $keys = $wp_query->fill_query_vars( array() );
4699
- }
4700
- else {
4701
- $tmp = new WP_Query();
4702
- $keys = $tmp->fill_query_vars( array() );
4703
- }
4704
-
4705
- $wp_keys = array_keys( $keys ); // WordPress GET fields for frontend
4706
-
4707
- $wp_keys[] = 'redirect_to';
4708
- $wp_keys[] = 'reauth';
4709
- $wp_keys[] = 'action';
4710
- $wp_keys[] = '_wpnonce';
4711
- $wp_keys[] = 'loggedout';
4712
-
4713
- // WP Customizer fields
4714
- $wp_keys = array_merge($wp_keys, array( 'nonce', '_method', 'wp_customize', 'changeset_uuid', 'customize_changeset_uuid', 'customize_theme', 'theme', 'customize_messenger_channel', 'customize_autosaved' ));
4715
-
4716
- $ret = array_diff( $get_keys, $wp_keys );
4717
-
4718
- if ( ! $ret ) {
4719
- $ret = array();
4720
- }
4721
-
4722
- return $ret;
4723
-
4724
- }
4725
-
4726
-
4727
- /**
4728
- *
4729
- * @since 6.0
4730
- */
4731
- function cerber_beast(){
4732
- global $cerber_status;
4733
-
4734
- if ( is_admin()
4735
- || ( defined( 'DOING_CRON' ) && DOING_CRON )
4736
- || ( defined( 'WP_CLI' ) && WP_CLI )
4737
- ) {
4738
- return;
4739
- }
4740
-
4741
- if ( !crb_get_settings( 'tienabled' ) ) {
4742
- return;
4743
- }
4744
-
4745
- $acl = cerber_acl_check();
4746
- if ( $acl == 'W' ) {
4747
- return;
4748
- }
4749
-
4750
- $uri = cerber_purify_uri();
4751
-
4752
- if ( $tiwhite = crb_get_settings( 'tiwhite' ) ) {
4753
- foreach ( (array)$tiwhite as $item ) {
4754
- if ($item == $uri){
4755
- return;
4756
- }
4757
- }
4758
- }
4759
-
4760
- $uri_script = cerber_get_uri_script();
4761
-
4762
- if ( $uri_script && $script_filename = cerber_script_filename() ) {
4763
- // Scaning for executable scripts?
4764
- if ( false === strrpos( $script_filename, $uri ) ) {
4765
- $wp_cerber = get_wp_cerber();
4766
- $cerber_status = 13;
4767
- cerber_log( 55 );
4768
- cerber_soft_block_add( $wp_cerber->getRemoteIp(), 8);
4769
- //cerber_404_page( true );
4770
- cerber_forbidden_page();
4771
- }
4772
- // Direct access to PHP script
4773
- // TODO: add white list setting for permitted URI like query white list
4774
- if ( ! in_array( $uri_script, cerber_get_wp_scripts() ) ) {
4775
- $deny = false;
4776
- if ( $acl == 'B' ) {
4777
- $deny = true;
4778
- $cerber_status = 14;
4779
- }
4780
- elseif (!cerber_is_allowed() ) {
4781
- $deny = true;
4782
- $cerber_status = 13;
4783
- }
4784
- elseif ( lab_is_blocked( null, true ) ) {
4785
- $deny = true;
4786
- $cerber_status = 15;
4787
- }
4788
- if ($deny){
4789
- cerber_log( 50 );
4790
- //cerber_404_page( true );
4791
- cerber_forbidden_page();
4792
- }
4793
- }
4794
- }
4795
- }
1
+ <?php
2
+ /*
3
+ Plugin Name: WP Cerber Security & Antispam
4
+ Plugin URI: https://wpcerber.com
5
+ Description: Protects WordPress against brute force attacks, bots and hackers. Antispam protection with the Cerber antispam engine and reCAPTCHA. Comprehensive control of user and bot activity. Restrict login by IP access lists. Limit login attempts. Know more: <a href="https://wpcerber.com">wpcerber.com</a>.
6
+ Author: Gregory
7
+ Author URI: https://wpcerber.com
8
+ Version: 6.5
9
+ Text Domain: wp-cerber
10
+ Domain Path: /languages
11
+ Network: true
12
+
13
+ Copyright (C) 2015-18 CERBER TECH INC., http://cerber.tech
14
+ Copyright (C) 2015-18 Gregory Markov, https://wpcerber.com
15
+
16
+ Licenced under the GNU GPL.
17
+
18
+ This program is free software; you can redistribute it and/or modify
19
+ it under the terms of the GNU General Public License as published by
20
+ the Free Software Foundation; either version 3 of the License, or
21
+ (at your option) any later version.
22
+
23
+ This program is distributed in the hope that it will be useful,
24
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
25
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26
+ GNU General Public License for more details.
27
+
28
+ You should have received a copy of the GNU General Public License
29
+ along with this program; if not, write to the Free Software
30
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
31
+
32
+ */
33
+
34
+ define( 'CERBER_VER', '6.5' );
35
+
36
+ function cerber_plugin_file() {
37
+ return __FILE__;
38
+ }
39
+ function cerber_plug_in() {
40
+ return plugin_basename( __FILE__ );
41
+ }
42
+ function cerber_plugin_data() {
43
+ return get_plugin_data( __FILE__ );
44
+ }
45
+ function cerber_plugin_dir_url() {
46
+ return plugin_dir_url( __FILE__ );
47
+ }
48
+
49
+ require_once( dirname( __FILE__ ) . '/cerber-load.php' );
50
+ cerber_init();
51
+