Server :
Apache
System :
Linux webd003.cluster126.gra.hosting.ovh.net 5.15.206-ovh-vps-grsec-zfs-classid #1 SMP Fri May 15 02:41:25 UTC 2026 x86_64
User :
atwiofrxug (73666)
PHP Version :
8.4.10
Disable Functions :
_dyuweyrj4,_dyuweyrj4r,dl
Current Directory :
/home/atwiofrxug/mylittletelaviv/wp-content/plugins/wp-cerber/
Directory Status:
Writeable | Document Root:
Writeable
Upload File
Viewing: /home/atwiofrxug/mylittletelaviv/wp-content/plugins/wp-cerber/cerber-load.php
<?php
/*
Copyright (C) 2015-19 CERBER TECH INC., http://cerber.tech
Copyright (C) 2015-19 CERBER TECH INC., https://wpcerber.com
Licenced under the GNU GPL.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
▄████▄ ▓█████ ██▀███ ▄▄▄▄ ▓█████ ██▀███
▒██▀ ▀█ ▓█ ▀ ▓██ ▒ ██▒ ▓█████▄ ▓█ ▀ ▓██ ▒ ██▒
▒▓█ ▄ ▒███ ▓██ ░▄█ ▒ ▒██▒ ▄██ ▒███ ▓██ ░▄█ ▒
▒▓▓▄ ▄██▒ ▒▓█ ▄ ▒██▀▀█▄ ▒██░█▀ ▒▓█ ▄ ▒██▀▀█▄
▒ ▓███▀ ░ ░▒████▒ ░██▓ ▒██▒ ░▓█ ▀█▓ ░▒████▒ ░██▓ ▒██▒
░ ░▒ ▒ ░ ░░ ▒░ ░ ░ ▒▓ ░▒▓░ ░▒▓███▀▒ ░░ ▒░ ░ ░ ▒▓ ░▒▓░
░ ▒ ░ ░ ░ ░▒ ░ ▒░ ▒░▒ ░ ░ ░ ░ ░▒ ░ ▒░
░ ░ ░░ ░ ░ ░ ░ ░░ ░
░ ░ ░ ░ ░ ░ ░ ░ ░
░ ░
*========================================================================*
| |
| ATTENTION! Do not change or edit this file! |
| |
*========================================================================*
*/
// If this file is called directly, abort executing.
if ( ! defined( 'WPINC' ) ) {
exit;
}
define( 'CERBER_LOG_TABLE', 'cerber_log' );
define( 'CERBER_QMEM_TABLE', 'cerber_qmem' );
define( 'CERBER_TRAF_TABLE', 'cerber_traffic' );
define( 'CERBER_ACL_TABLE', 'cerber_acl' );
define( 'CERBER_BLOCKS_TABLE', 'cerber_blocks' );
define( 'CERBER_LAB_TABLE', 'cerber_lab' );
define( 'CERBER_LAB_IP_TABLE', 'cerber_lab_ip' );
define( 'CERBER_LAB_NET_TABLE', 'cerber_lab_net' );
define( 'CERBER_GEO_TABLE', 'cerber_countries' );
define( 'CERBER_SCAN_TABLE', 'cerber_files' );
define( 'CERBER_SETS_TABLE', 'cerber_sets' );
define( 'CERBER_MS_TABLE', 'cerber_ms' );
define( 'CERBER_MS_LIST_TABLE', 'cerber_ms_lists' );
define( 'CERBER_BUKEY', '_crb_blocked' );
define( 'CERBER_PREFIX', '_cerber_' );
define( 'CERBER_MARKER1', 'WP CERBER GROOVE' );
define( 'CERBER_MARKER2', 'WP CERBER CLAMPS' );
define( 'CERBER_NO_REMOTE_IP', '0.0.0.0' );
define( 'WP_LOGIN_SCRIPT', 'wp-login.php' );
define( 'WP_REG_URI', 'wp-register.php' );
define( 'WP_SIGNUP_SCRIPT', 'wp-signup.php' );
define( 'WP_XMLRPC_SCRIPT', 'xmlrpc.php' );
define( 'WP_TRACKBACK_SCRIPT', 'wp-trackback.php' );
define( 'WP_PING_SCRIPT', 'wp-trackback.php' );
define( 'WP_COMMENT_SCRIPT', 'wp-comments-post.php' );
define( 'GOO_RECAPTCHA_URL', 'https://www.google.com/recaptcha/api/siteverify' );
define( 'CERBER_VULNDB_API', 'https://wpvulndb.com/api/v2/plugins/' );
define( 'CERBER_REQ_PHP', '5.4.0' );
define( 'CERBER_REQ_WP', '4.5' );
define( 'CERBER_TECH', 'https://cerber.tech/' );
define( 'CERBER_CIREC_LIMIT', 30 ); // Upper limit for allowed nested values during inspection for malware
define( 'CERBER_AGGRESSIVE', 1 );
require_once( dirname( __FILE__ ) . '/cerber-pluggable.php' );
require_once( dirname( __FILE__ ) . '/common.php' );
require_once( dirname( __FILE__ ) . '/settings.php' );
include_once( dirname( __FILE__ ) . '/cerber-request.php' );
require_once( dirname( __FILE__ ) . '/cerber-lab.php' );
require_once( dirname( __FILE__ ) . '/whois.php' );
require_once( dirname( __FILE__ ) . '/jetflow.php' );
require_once( dirname( __FILE__ ) . '/cerber-news.php' );
require_once( dirname( __FILE__ ) . '/cerber-scanner.php' );
require_once( dirname( __FILE__ ) . '/nexus/cerber-nexus.php' );
if ( defined( 'WP_ADMIN' ) || defined( 'WP_NETWORK_ADMIN' ) ) {
// Load dashboard stuff
//require_once( dirname( __FILE__ ) . '/cerber-users.php' );
//require_once( dirname( __FILE__ ) . '/dashboard.php' );
cerber_load_admin_code();
}
// =============================================================================================
class WP_Cerber {
private $remote_ip;
private $session_id;
private $status = null;
private $options;
private $locked = null; // IP has been locked out
private $recaptcha = null; // Can recaptcha be verified with current request
private $recaptcha_verified = null; // Is recaptcha successfully verified with current request
public $recaptcha_here = null; // Is recaptcha widget enabled on the currently displayed page
private $uri_prohibited = null;
private $deny = null;
private $acl = null;
//private $boot_source_file = '';
//private $boot_target_file = '';
public $garbage = false; // Garbage has been deleted
final function __construct() {
$this->session_id = substr(str_shuffle('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'), 0, 24);
// Load settings with filling missing (not-set) array keys
$this->options = crb_get_settings(); // @since 6.3.3
$keys = array();
//$defaults = array();
foreach ( cerber_get_defaults() as $item ) {
$keys = array_merge( $keys, array_keys( $item ) );
//$defaults = array_merge( $defaults, $item );
}
foreach ( $keys as $key ) {
if ( ! isset( $this->options[ $key ] ) ) {
$this->options[ $key ] = null;
}
}
if ( defined( 'CERBER_IP_KEY' ) ) {
$this->remote_ip = filter_var( $_SERVER[ CERBER_IP_KEY ], FILTER_VALIDATE_IP );
}
elseif ( $this->options['proxy'] && isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
$list = explode( ',', $_SERVER['HTTP_X_FORWARDED_FOR'] );
foreach ( $list as $maybe_ip ) {
$this->remote_ip = filter_var( trim( $maybe_ip ), FILTER_VALIDATE_IP );
if ( $this->remote_ip ) {
break;
}
}
if ( ! $this->remote_ip && isset( $_SERVER['HTTP_X_REAL_IP'] ) ) {
$this->remote_ip = filter_var( $_SERVER['HTTP_X_REAL_IP'], FILTER_VALIDATE_IP );
}
} else {
if ( isset( $_SERVER['REMOTE_ADDR'] ) ) {
$this->remote_ip = $_SERVER['REMOTE_ADDR'];
} elseif ( isset( $_SERVER['HTTP_X_REAL_IP'] ) ) {
$this->remote_ip = $_SERVER['HTTP_X_REAL_IP'];
} elseif ( isset( $_SERVER['HTTP_CLIENT_IP'] ) ) {
$this->remote_ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif ( isset( $_SERVER['SERVER_ADDR'] ) ) {
$this->remote_ip = $_SERVER['SERVER_ADDR'];
}
$this->remote_ip = filter_var( $this->remote_ip, FILTER_VALIDATE_IP );
}
// No IP address was found? Roll back to localhost.
if ( ! $this->remote_ip ) { // including WP-CLI, other way is: if defined('WP_CLI')
$this->remote_ip = CERBER_NO_REMOTE_IP;
}
$this->remote_ip = cerber_short_ipv6( $this->remote_ip );
$this->reCaptchaInit();
$this->deleteGarbage();
// Condition to check reCAPTCHA
add_action( 'login_init', array( $this, 'reCaptchaNow' ) );
}
/**
* @since 6.3.3
*/
final public function isURIProhibited() {
global $cerber_status;
if ( isset( $this->uri_prohibited ) ) {
return $this->uri_prohibited;
}
if ( crb_acl_is_white() ) {
$this->uri_prohibited = false;
return false;
}
$script = cerber_last_uri();
$script = urldecode( $script ); // @since 8.1
if ( substr( $script, - 4 ) != '.php' ) {
$script .= '.php'; // Apache MultiViews enabled?
}
if ( $script ) {
if ( $script == WP_LOGIN_SCRIPT
|| $script == WP_SIGNUP_SCRIPT
|| ( $script == WP_REG_URI && ! get_option( 'users_can_register' ) ) ) {
if ( !empty( $this->options['wplogin'] ) ) {
$cerber_status = 19;
cerber_log( 50 );
cerber_soft_block_add( $this->remote_ip, 702, $script );
$this->uri_prohibited = true;
return true;
}
if ( ! empty( $this->options['loginnowp'] )
|| $this->isDeny() ) {
cerber_log( 50 );
$this->uri_prohibited = true;
return true;
}
}
elseif ( $script == WP_XMLRPC_SCRIPT || $script == WP_TRACKBACK_SCRIPT ) {
if ( ! empty( $this->options['xmlrpc'] )
|| $this->isDeny() ) {
cerber_log( 71 );
$this->uri_prohibited = true;
return true;
}
if ( !cerber_geo_allowed( 'geo_xmlrpc' ) ) {
$cerber_status = 16;
cerber_log( 71 );
$this->uri_prohibited = true;
return true;
}
}
}
$this->uri_prohibited = false;
return $this->uri_prohibited;
}
/**
* @since 6.3.3
*/
final public function CheckProhibitedURI(){
if ($this->isURIProhibited()){
if ( $this->options['page404'] ) {
cerber_404_page();
}
return true;
}
return false;
}
/**
* @since 6.3.3
*/
final public function InspectRequest() {
$deny = false;
$act = 18;
if ( cerber_is_http_post() ) {
if ( ! cerber_is_allowed( null, array( 701, 703, 704 ) ) ) {
$deny = true;
$act = 18;
}
}
elseif ( cerber_get_non_wp_fields() ) {
if ( ! cerber_is_allowed() ) {
$deny = true;
$act = 100;
}
}
if ( ! $deny && $_FILES ) {
$file_names = array();
foreach ( $_FILES as $file ) {
if ( is_array( $file['name'] ) ) {
$file_names = array_merge( $file_names, $file['name'] );
}
else {
$file_names[] = $file['name'];
}
}
foreach ( $file_names as $item ) {
if ( $reason = $this->isProhibitedFilename( $item ) ) {
$deny = true;
$act = $reason;
break;
}
}
}
if ( $deny ) {
cerber_log( $act );
cerber_forbidden_page();
}
}
/**
* @since 6.3.3
*/
final public function isProhibitedFilename( $file_name ) {
$prohibited = array( '.htaccess' );
if ( in_array( $file_name, $prohibited ) ) {
return 57;
}
if ( cerber_detect_exec_extension( $file_name, array('js') ) ) {
return 56;
}
return false;
}
/**
* @since 6.3.3
*/
final public function isDeny() {
if ( isset( $this->deny ) ) {
return $this->deny;
}
$this->acl = cerber_acl_check();
if ( $this->acl == 'B' || ! cerber_is_allowed() ) {
$this->deny = true;
}
else {
$this->deny = false;
}
return $this->deny;
}
// TODO: replace it with cerber_get_remote_ip()
final public function getRemoteIp() {
return $this->remote_ip;
}
final public function getSessionID() {
return $this->session_id;
}
final public function getStatus() {
if (isset($this->status)) return $this->status;
$this->status = 0; // Default
if ( cerber_is_citadel() ) {
$this->status = 3;
}
else {
//if ( ! cerber_is_allowed( $this->remote_ip ) ) {
if ( cerber_block_check( $this->remote_ip ) ) {
$this->status = 2;
}
else {
$tag = cerber_acl_check( $this->remote_ip );
if ( $tag == 'W' ) {
//$this->status = 4;
}
elseif ( $tag == 'B' || lab_is_blocked($this->remote_ip, false)) {
$this->status = 1;
}
}
}
return $this->status;
}
/*
Return Error message in context
*/
final public function getErrorMsg() {
$status = $this->getStatus();
switch ( $status ) {
case 1:
case 3:
return apply_filters( 'cerber_msg_blocked', __( 'You are not allowed to log in. Ask your administrator for assistance.', 'wp-cerber' ) , $status);
case 2:
$block = cerber_get_block();
$min = 1 + ( $block->block_until - time() ) / 60;
return apply_filters( 'cerber_msg_reached',
sprintf( __( 'You have exceeded the number of allowed login attempts. Please try again in %d minutes.', 'wp-cerber' ), $min ),
$min );
break;
default:
return __( 'You are not allowed to log in', 'wp-cerber' );
}
}
/*
Return Remain message in context
*/
final public function getRemainMsg() {
$acl = !$this->options['limitwhite'];
$remain = cerber_get_remain_count($this->remote_ip, $acl);
if ( $remain < $this->options['attempts'] ) {
if ( $remain == 0 ) {
$remain = 1; // with some settings or when lockout was manually removed, we need to have 1 attempt.
}
return apply_filters( 'cerber_msg_remain',
sprintf( _n( 'You have only one attempt remaining.', 'You have %d attempts remaining.', $remain, 'wp-cerber' ), $remain ),
$remain );
}
return false;
}
final public function getSettings( $name = null ) {
if ( ! empty( $name ) ) {
if ( isset( $this->options[ $name ] ) ) {
return $this->options[ $name ];
} else {
return false;
}
}
return $this->options;
}
/*
final public function isProhibited( $username ) {
if ( empty( $this->options['prohibited'] ) ) {
return false;
}
return in_array( $username, (array) $this->options['prohibited'] );
}*/
/**
* Adding reCAPTCHA widgets
*
*/
final public function reCaptchaInit(){
if ( $this->status == 4 || empty( $this->options['sitekey'] ) || empty( $this->options['secretkey'] )) return;
// Native WP forms
add_action( 'login_form', function () {
global $wp_cerber;
$wp_cerber->reCaptcha( 'widget', 'recaplogin' );
} );
add_filter( 'login_form_middle', function ( $value ) {
global $wp_cerber;
$value .= $wp_cerber->reCaptcha( 'widget', 'recaplogin', false );
return $value;
});
add_action( 'lostpassword_form', function () {
global $wp_cerber;
$wp_cerber->reCaptcha( 'widget', 'recaplost' );
} );
add_action( 'register_form', function () {
global $wp_cerber;
if ( !did_action( 'woocommerce_register_form_start' ) ) {
$wp_cerber->reCaptcha( 'widget', 'recapreg' );
}
} );
// Support for WooCommerce forms: @since 3.8
add_action( 'woocommerce_login_form', function () {
global $wp_cerber;
$wp_cerber->reCaptcha( 'widget', 'recapwoologin' );
} );
add_action( 'woocommerce_lostpassword_form', function () {
global $wp_cerber;
$wp_cerber->reCaptcha( 'widget', 'recapwoolost' );
} );
add_action( 'woocommerce_register_form', function () {
global $wp_cerber;
if ( ! did_action( 'woocommerce_register_form_start' ) ) {
return;
}
$wp_cerber->reCaptcha( 'widget', 'recapwooreg' );
} );
add_filter( 'woocommerce_process_login_errors', function ( $validation_error ) {
global $wp_cerber;
//$wp_cerber->reCaptchaNow();
if ( ! $wp_cerber->reCaptchaValidate('woologin', true) ) {
return new WP_Error( 'incorrect_recaptcha', $wp_cerber->reCaptchaMsg('woocommerce-login'));
}
return $validation_error;
});
add_filter( 'allow_password_reset', function ( $var ) { // Note: 'allow_password_reset' also is fired in WP itself
global $wp_cerber;
if ( isset( $_POST['wc_reset_password'] ) && did_action( 'woocommerce_init' )) {
//$wp_cerber->reCaptchaNow();
if ( ! $wp_cerber->reCaptchaValidate( 'woolost' , true) ) {
return new WP_Error( 'incorrect_recaptcha', $wp_cerber->reCaptchaMsg('woocommerce-lost'));
}
}
return $var;
});
add_filter( 'woocommerce_process_registration_errors', function ( $validation_error ) {
global $wp_cerber;
//$wp_cerber->reCaptchaNow();
if ( ! $wp_cerber->reCaptchaValidate('wooreg' , true) ) {
return new WP_Error( 'incorrect_recaptcha', $wp_cerber->reCaptchaMsg('woocommerce-register'));
}
return $validation_error;
});
}
/**
* Generates reCAPTCHA HTML
*
* @param string $part 'style' or 'widget'
* @param null $option what plugin setting must be set to show the reCAPTCHA
* @param bool $echo if false, return the code, otherwise show it
*
* @return null|string
*/
final public function reCaptcha( $part = '', $option = null, $echo = true ) {
if ( $this->status == 4 || empty( $this->options['sitekey'] ) || empty( $this->options['secretkey'] )
|| ( $option && empty( $this->options[ $option ] ) )
) {
return null;
}
$sitekey = $this->options['sitekey'];
$ret = '';
switch ( $part ) {
case 'style': // for default login WP form only - fit it in width nicely.
?>
<style type="text/css" media="all">
#rc-imageselect, .g-recaptcha {
transform: scale(0.9);
-webkit-transform: scale(0.9);
transform-origin: 0 0;
-webkit-transform-origin: 0 0;
}
.g-recaptcha {
margin: 16px 0 20px 0;
}
</style>
<?php
break;
case 'widget':
if ( ! empty( $this->options[ $option ] ) ) {
$this->recaptcha_here = true;
//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>';
if ($this->options['invirecap']) {
$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>';
}
else $ret = '<span class="cerber-form-marker"></span><div class="g-recaptcha" data-sitekey="' . $sitekey . '" data-callback="form_button_enabler" id="cerber-recaptcha"></div>';
//$ret = '<span class="cerber-form-marker g-recaptcha"></span>';
}
break;
}
if ( $echo ) {
echo $ret;
$ret = null;
}
return $ret;
/*
<script type="text/javascript">
var onloadCallback = function() {
//document.getElementById("wp-submit").disabled = true;
grecaptcha.render("c-recaptcha", {"sitekey" : "<?php echo $sitekey; ?>" });
//document.getElementById("wp-submit").disabled = false;
};
</script>
<script src = "https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit&hl=<?php echo $lang; ?>" async defer></script>
*/
}
/**
* Validate reCAPTCHA by calling Google service
*
* @param string $form Form ID (slug)
* @param boolean $force Force validate without pre-checks
*
* @return bool true on success false on failure
*/
final public function reCaptchaValidate($form = null, $force = false) {
if (!$force) {
if ( ! $this->recaptcha || $this->status == 4 ) {
return true;
}
}
if ($this->recaptcha_verified != null) return $this->recaptcha_verified;
if ( $form == 'comment' && $this->options['recapcomauth'] && is_user_logged_in()) return true;
if ( ! $form ) {
$form = isset( $_REQUEST['action'] ) ? $_REQUEST['action'] : 'login';
}
$forms = array( // known pairs: form => specific plugin setting
'lostpassword' => 'recaplost',
'register' => 'recapreg',
'login' => 'recaplogin',
'comment' => 'recapcom',
'woologin' => 'recapwoologin',
'woolost' => 'recapwoolost',
'wooreg' => 'recapwooreg',
);
if ( isset( $forms[ $form ] ) ) {
if ( empty( $this->options[ $forms[ $form ] ] ) ) {
return true; // no validation is required
}
}
else {
return true; // we don't know this form
}
if ( empty( $_POST['g-recaptcha-response'] ) ) {
$this->reCaptchaFailed($form);
return false;
}
$result = $this->reCaptchaRequest($_POST['g-recaptcha-response']);
if ( ! $result ) {
cerber_log( 42 );
return false;
}
$result = json_decode( $result );
$result = obj_to_arr_deep( $result );
if ( ! empty( $result['success'] ) ) {
$this->recaptcha_verified = true;
return true;
}
$this->recaptcha_verified = false;
if ( ! empty( $result['error-codes'] ) ) {
if ( in_array( 'invalid-input-secret', (array) $result['error-codes'] ) ) {
cerber_log( 41 );
}
}
$this->reCaptchaFailed($form);
return false;
}
final function reCaptchaFailed($context = '') {
cerber_log( 40 );
if ($this->options['recaptcha-period'] && $this->options['recaptcha-number'] && $this->options['recaptcha-within']) {
$remain = cerber_get_remain_count($this->remote_ip , true, array( 40 ), $this->options['recaptcha-number'], $this->options['recaptcha-within']);
if ($remain < 1) cerber_block_add( $this->remote_ip, 705 );
}
}
/**
* A form with possible reCAPTCHA has been submitted.
* Allow to process reCAPTCHA by setting a global flag.
* Must be called before reCaptchaValidate();
*
*/
final public function reCaptchaNow() {
if ( cerber_is_http_post() && $this->options['sitekey'] && $this->options['secretkey'] ) {
$this->recaptcha = true;
}
}
/**
* Make a request to the Google reCaptcha web service
*
* @param string $response Google specific field from the submitted form (widget)
*
* @return bool|string Response of the Google service or false on failure
*/
final public function reCaptchaRequest($response = ''){
if (!$response) {
if (!empty($_POST['g-recaptcha-response'])) $response = $_POST['g-recaptcha-response'];
else return false;
}
$curl = @curl_init(); // @since 4.32
if (!$curl) {
cerber_admin_notice(__( 'ERROR:', 'wp-cerber' ) .' Unable to initialize cURL');
return false;
}
$opt = curl_setopt_array($curl, array(
CURLOPT_URL => GOO_RECAPTCHA_URL,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => array( 'secret' => $this->options['secretkey'], 'response' => $response ),
CURLOPT_RETURNTRANSFER => true,
));
if (!$opt) {
cerber_admin_notice(__( 'ERROR:', 'wp-cerber' ) .' '. curl_error($curl));
curl_close($curl);
return false;
}
$result = @curl_exec($curl);
if (!$result) {
cerber_admin_notice(__( 'ERROR:', 'wp-cerber' ) .' '. curl_error($curl));
$result = false;
}
curl_close($curl);
return $result;
}
final public function reCaptchaMsg($context = null){
return apply_filters( 'cerber_msg_recaptcha', __( 'Human verification failed. Please click the square box in the reCAPTCHA block below.', 'wp-cerber' ), $context);
}
final public function setLocked() {
if ( ! isset( $this->locked ) ) {
$this->locked = 1;
}
}
final public function wasLocked() {
if ( ! empty( $this->locked ) ) {
return 1;
}
return 0;
}
final public function deleteGarbage() {
if ( $this->garbage ) {
return;
}
cerber_db_query( 'DELETE FROM ' . CERBER_BLOCKS_TABLE . ' WHERE block_until < ' . time() );
$this->garbage = true;
}
}
function cerber_init() {
static $done = false;
if ( $done ) {
return;
}
cerber_pre_checks();
cerber_error_control();
if ( crb_get_settings( 'tiphperr' ) ) {
set_error_handler( 'cerber_catch_error' );
}
cerber_upgrade_all();
global $wp_cerber;
$wp_cerber = get_wp_cerber();
cerber_beast();
$antibot = cerber_antibot_gene();
if ( $antibot && ! empty( $antibot[1] ) ) {
foreach ( $antibot[1] as $item ) {
setcookie( $item[0], $item[1], time() + 3600 * 24, cerber_get_cookie_path() );
}
}
// Redirection control: no default aliases for redirections
//if ( crb_get_settings( 'noredirect' ) ) {
if ( cerber_no_redirect() ) {
remove_action( 'template_redirect', 'wp_redirect_admin_locations', 1000 );
}
$hooks = apply_filters( 'cerber_antibot_hooks', array() );
if ( ! empty( $hooks['login_register'] ) ) {
foreach ( $hooks['login_register'] as $hook ) {
add_action( $hook, 'cerber_login_register_stuff', 1000 );
}
}
$done = true;
}
/**
* Returns correct WP_Cerber object
* Protects and sets global $wp_cerber to the proper object
*
* @return WP_Cerber
* @since 6.0
*/
function get_wp_cerber(){
global $wp_cerber;
static $the_wp_cerber = null;
if ( ! isset( $the_wp_cerber ) ) {
$the_wp_cerber = new WP_Cerber();
}
$wp_cerber = $the_wp_cerber;
return $the_wp_cerber;
}
/**
*
* Initialize Cerber Security
*
*/
add_action( 'plugins_loaded', function () {
cerber_error_control();
get_wp_cerber();
cerber_inspect_uploads(); // Uploads in the dashboard
$use_eng = false;
//if ( is_admin() && crb_get_settings( 'admin_lang' ) && cerber_is_admin_page() ) {
if ( is_admin() && crb_get_settings( 'admin_lang' ) ) {
$use_eng = true;
//add_filter( 'locale', function () {
/*add_filter( 'plugin_locale', function () {
return 'en_US';
} );*/
add_filter( 'override_load_textdomain', function ( $val, $domain, $mofile ) {
if ($domain == 'wp-cerber'){
$val = true;
}
return $val;
}, 100, 3 );
}
if ( ! $use_eng ) {
load_plugin_textdomain( 'wp-cerber', false, basename( dirname( __FILE__ ) ) . '/languages' );
}
/* @since 5.8.8
if ( ! cerber_check_groove() && ! cerber_is_allowed() ) {
wp_clear_auth_cookie();
}*/
cerber_init_cron();
__('> > > Translator of WP Cerber? To get the PRO license for free, drop your contacts here: https://wpcerber.com/contact/','wp-cerber');
}, 1000 );
function cerber_load_admin_code() {
require_once( dirname( __FILE__ ) . '/cerber-users.php' );
require_once( dirname( __FILE__ ) . '/dashboard.php' );
require_once( dirname( __FILE__ ) . '/cerber-maintenance.php' );
}
/**
* Some additional tasks...
*
*/
function cerber_extra_vision() {
global $cerber_logged, $cerber_status;
// Multiple different malicious activities
if ( ! empty( $cerber_logged ) ) {
$ip = cerber_get_remote_ip();
$black = crb_get_activity_set( 'black' );
$black_logged = array_intersect( $black, $cerber_logged );
if ( ! empty( $black_logged ) && cerber_is_allowed() ) {
$remain = cerber_get_remain_count( $ip, true, $black ); // @since 6.7.5
if ( $remain < 1 ) {
cerber_soft_block_add( $ip, 707 );
$cerber_status = 18;
return true;
}
}
}
return false;
}
/*
Display login form if Custom login URL has been requested
*/
add_action( 'init', 'cerber_wp_login_page', 20 );
//add_action( 'setup_theme', 'cerber_wp_login_page' ); // @since 5.05
function cerber_wp_login_page() {
if ( $path = crb_get_settings( 'loginpath' ) ) {
if ( cerber_is_login_request() ) {
if ( ! defined( 'DONOTCACHEPAGE' ) ) {
define( 'DONOTCACHEPAGE', true ); // @since 5.7.6
}
@ini_set( 'display_startup_errors', 0 );
@ini_set( 'display_errors', 0 );
add_action( 'login_init', function () {
@ini_set( 'display_startup_errors', 0 );
@ini_set( 'display_errors', 0 );
} );
require( ABSPATH . WP_LOGIN_SCRIPT ); // load default wp-login.php form
exit;
}
}
}
/**
* Check if the current HTTP request is a login/register/lost password page request
*
* @return bool
*/
function cerber_is_login_request() {
static $ret;
if ( isset( $ret ) ) {
return $ret;
}
$ret = false;
if ( $path = crb_get_settings( 'loginpath' ) ) {
$request = $_SERVER['REQUEST_URI'];
if ( $pos = strpos( $request, '?' ) ) {
$request = substr( $request, 0, $pos - 1 );
}
$request = explode( '/', rtrim( $request, '/' ) );
$request = end( $request );
if ( $path == $request && ! cerber_is_rest_url() ) {
$ret = true;
}
}
elseif ( CRB_Request::is_script( '/' . WP_LOGIN_SCRIPT ) ) {
$ret = true;
}
return $ret;
}
/**
* Does the current location (URL) requires a user to be logged in to view
*
* @param $allowed_url string An URL that is allowed to view without authentication
*
* @return bool
*/
function cerber_auth_required( $allowed_url ) {
if ( $allowed_url && CRB_Request::is_url_equal( $allowed_url ) ) {
return false;
}
if ( cerber_is_login_request() ) {
return false;
}
if ( CRB_Request::is_script( array( '/' . WP_LOGIN_SCRIPT, '/' . WP_SIGNUP_SCRIPT, '/wp-activate.php' ) ) ) {
return false;
}
if ( CRB_Request::is_url_start_with( wp_login_url() ) ) {
return false;
}
if ( class_exists( 'WooCommerce' ) ) {
if ( CRB_Request::is_url_start_with( get_permalink( get_option( 'woocommerce_myaccount_page_id' ) ) ) ) {
return false;
}
}
return true;
}
/*
Create message to show it above login form for any simply GET
*/
add_action( 'login_head', 'cerber_login_head' );
function cerber_login_head() {
global $error, $wp_cerber;
if ( !$allowed = cerber_is_allowed() ) :
?>
<style type="text/css" media="all">
#loginform {
display: none;
}
</style>
<?php
endif;
$wp_cerber->reCaptcha( 'style' );
if ( !cerber_is_http_get() ) {
return;
}
if ( ! cerber_can_msg() ) {
return;
}
if ( ! $allowed ) {
$error = $wp_cerber->getErrorMsg();
}
elseif ( $msg = $wp_cerber->getRemainMsg() ) {
$error = $msg;
}
elseif ( crb_get_settings( 'authonly' ) && ( $m = crb_get_settings( 'authonlymsg' ) ) ) {
$error = $m;
}
}
/**
* Control the process of authentication
*
* @since 2.9
*
*/
remove_filter( 'authenticate', 'wp_authenticate_username_password', 20 );
remove_filter( 'authenticate', 'wp_authenticate_email_password', 20 );
add_filter( 'authenticate', function ( $user, $username, $password ) {
return cerber_authenticate( $user, $username, $password );
}, 20, 3 );
function cerber_authenticate( $user, $username, $password ) {
global $wp_cerber;
if ( ! $wp_cerber->reCaptchaValidate() ) {
return new WP_Error( 'incorrect_recaptcha',
'<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
$wp_cerber->reCaptchaMsg('login'));
}
// Check for prohibited username
//if ( $wp_cerber->isProhibited( $username ) ) {
if ( $username && cerber_is_prohibited( $username ) ) {
cerber_log( 52, $username );
cerber_block_add( null, 704, $username );
// Create with message that is identical default WP
return new WP_Error( 'incorrect_password', sprintf(
__( '<strong>ERROR</strong>: The password you entered for the username %s is incorrect.' ),
'<strong>' . $username . '</strong>'
) );
}
/*
if ( lab_is_blocked($wp_cerber->getRemoteIp()) ) {
// Create with message which is identical default WP
return new WP_Error( 'incorrect_password', sprintf(
__( '<strong>ERROR</strong>: The password you entered for the username %s is incorrect.' ),
'<strong>' . $username . '</strong>'
) );
}*/
$user = wp_authenticate_username_password( $user, $username, $password );
$user = wp_authenticate_email_password( $user, $username, $password );
// @since 4.18 it is replacement for 'wp_login_failed' action hook
// see WP function wp_authenticate()
$ignore_codes = array( 'empty_username', 'empty_password', 'cerber_denied' );
if ( is_wp_error( $user ) && ! in_array( $user->get_error_code(), $ignore_codes ) ) {
$user_id = null;
if ( ( $data = $user->get_error_data() ) && ! empty( $data['user_id'] ) ) {
$user_id = $data['user_id'];
}
cerber_login_failed( $username, $user_id );
}
return $user;
}
/*
Stop the authentication process for an existing user
Invoking in:
'wp_authenticate_username_password()'
'wp_authenticate_email_password()'
*/
add_filter( 'wp_authenticate_user', 'cerber_stop_authentication', 9999, 2 );
function cerber_stop_authentication( $user, $password ) {
global $wp_cerber, $cerber_status;
$deny = false;
$user_msg = '';
if ( $b = crb_is_user_blocked( $user->ID ) ) {
$user_msg = $b['blocked_msg'];
$cerber_status = 25;
$deny = true;
}
elseif ( ! cerber_is_allowed() ) {
$deny = true;
}
elseif ( ! cerber_geo_allowed( 'geo_login' ) ) {
$cerber_status = 16;
$deny = true;
}
elseif ( lab_is_blocked( $wp_cerber->getRemoteIp() ) ) {
$cerber_status = 15;
$deny = true;
}
if ( $deny ) {
status_header( 403 );
$error = new WP_Error();
if ( ! $user_msg ) {
$user_msg = $wp_cerber->getErrorMsg();
}
$error->add( 'cerber_wp_error', $user_msg, array( 'user_id' => $user->ID ) );
return $error;
}
return $user;
}
/**
*
* Handler for failed login attempts
*
* @param $user_login
* @param int $user_id User ID
*
*/
//add_action( 'wp_login_failed', 'cerber_login_failed' ); // @since 4.18
function cerber_login_failed( $user_login, $user_id = 0 ) {
global $wpdb, $wp_cerber, $cerber_status;
static $is_processed = false;
if ( $is_processed ) return;
$is_processed = true;
$ip = $wp_cerber->getRemoteIp();
$acl = cerber_acl_check( $ip );
if ( ! cerber_get_user( $user_login ) ) {
$no_user = true;
}
else {
$no_user = false;
}
//cerber_failed_work($ip, $acl, $no_user, $user_login);
//if ( ! $wp_cerber->isProcessed() ) {
//if ( ! cerber_get_user( $user_login ) ) {
// $no_user = true;
//}
$ac = 7;
if ( $no_user ) {
$ac = 51;
}
elseif ( ! cerber_is_allowed( $ip ) || $cerber_status == 15 || $cerber_status == 16 || $cerber_status == 25 ) { // TODO should be refactored together with cerber_stop_authentication
$ac = 53;
}
/*
elseif ( $acl == 'B' ) {
$ac = 14;
}
elseif ( lab_is_blocked($ip, false) ) {
$ac = 53;
}
else {
$ac = 53;
}*/
cerber_log( $ac, $user_login, $user_id );
//}
// White? Stop further actions.
if ( $acl == 'W' && !crb_get_settings( 'limitwhite' )) {
return;
}
if ( crb_get_settings( 'usefile' ) ) {
cerber_file_log( $user_login, $ip );
}
if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) { // Needs additional researching and, maybe, refactoring
status_header( 403 );
}
// Blacklisted? No more actions are needed.
if ( $acl == 'B' ) {
return;
}
// Must the Citadel mode be activated?
if ( $wp_cerber->getSettings( 'ciperiod' ) && ! cerber_is_citadel() ) {
$range = time() - $wp_cerber->getSettings( 'ciperiod' ) * 60;
//$lockouts = $wpdb->get_var( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE activity IN (7,51,52) AND stamp > ' . $range );
$lockouts = cerber_db_get_var( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE activity IN (7,51,52) AND stamp > ' . $range );
if ( $lockouts >= $wp_cerber->getSettings( 'cilimit' ) ) {
cerber_enable_citadel();
}
}
if ( $no_user && $wp_cerber->getSettings( 'nonusers' ) ) {
cerber_block_add( $ip, 703, $user_login); // @since 5.7
}
elseif ( cerber_get_remain_count($ip, false) < 1 ) { //Limit on the number of login attempts is reached
cerber_block_add( $ip, 701, '', null, false);
}
}
/**
* Do the work with failed/blocked attempt
*
* @param $ip
* @param $acl
* @param $user_login
*/
function cerber_failed_work($ip, $acl, $no_user, $user_login){
global $wpdb, $wp_cerber;
// White? Stop further actions.
if ( $acl == 'W' && !$wp_cerber->getSettings( 'limitwhite' )) {
return;
}
if ( $wp_cerber->getSettings( 'usefile' ) ) {
cerber_file_log( $user_login, $ip );
}
if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) { // Needs additional researching and, maybe, refactoring
status_header( 403 );
}
// Blacklisted? No more actions are needed.
if ( $acl == 'B' ) {
return;
}
// Must the Citadel mode be activated?
if ( $wp_cerber->getSettings( 'ciperiod' ) && ! cerber_is_citadel() ) {
$range = time() - $wp_cerber->getSettings( 'ciperiod' ) * 60;
//$lockouts = $wpdb->get_var( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE activity IN (7,51,52) AND stamp > ' . $range );
$lockouts = cerber_db_get_var( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE activity IN (7,51,52) AND stamp > ' . $range );
if ( $lockouts >= $wp_cerber->getSettings( 'cilimit' ) ) {
cerber_enable_citadel();
}
}
if ( $no_user && $wp_cerber->getSettings( 'nonusers' ) ) {
cerber_block_add( $ip, 703, $user_login );
}
elseif ( cerber_get_remain_count($ip, false) <= 1 ) { //Limit on the number of login attempts is reached
cerber_block_add( $ip, 701, '', null, false);
}
}
// Validating the user, we use closure to make this unavoidable
add_action( 'set_current_user', function () { // the right way
cerber_validate_the_user();
}, 0 );
add_action( 'init', function () { // backup for 'set_current_user'
cerber_validate_the_user();
}, 0 );
function cerber_validate_the_user() {
global $current_user, $userdata, $user_ID;
$user = ( ! $current_user instanceof WP_User ) ? wp_get_current_user() : $current_user;
if ( crb_is_user_blocked( $user->ID ) ) {
@wp_logout();
$current_user = null;
$userdata = null;
$user_ID = null;
if ( is_admin() ) {
wp_redirect( cerber_get_home_url() );
}
else {
wp_safe_redirect( CRB_Request::full_url() );
}
exit;
}
}
// Registration -----------------------------------------------------------------------
function cerber_is_registration_prohibited( $sanitized_user_login ) {
global $wp_cerber, $cerber_status;
/*
if ( crb_acl_is_white() ) {
return false;
}*/
$code = null;
$msg = null;
if ( crb_is_reg_limit_reached() ) {
$cerber_status = 17;
cerber_log( 54 );
$code = 'ip_denied';
$msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
apply_filters( 'cerber_msg_denied', __( 'You are not allowed to register.', 'wp-cerber' ), 'register' );
}
elseif ( cerber_is_bot( 'botsreg' ) ) {
cerber_log( 54 ); // TODO should be separate code to detect bot activity?
$code = 'bot_detected';
$msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
apply_filters( 'cerber_msg_denied', __( 'You are not allowed to register.', 'wp-cerber' ), 'register' );
}
elseif ( ! $wp_cerber->reCaptchaValidate() ) {
$code = 'incorrect_recaptcha';
$msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
$wp_cerber->reCaptchaMsg( 'register' );
}
elseif ( cerber_is_prohibited( $sanitized_user_login ) ) {
$code = 'prohibited_login';
$msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
apply_filters( 'cerber_msg_prohibited', __( 'Username is not allowed. Please choose another one.', 'wp-cerber' ), 'register' );
}
elseif ( ! cerber_is_allowed() || lab_is_blocked( $wp_cerber->getRemoteIp() ) ) {
cerber_log( 54 );
$code = 'ip_denied';
$msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
apply_filters( 'cerber_msg_denied', __( 'You are not allowed to register.', 'wp-cerber' ), 'register' );
}
elseif ( ! cerber_geo_allowed( 'geo_register' ) ) {
$cerber_status = 16; // TODO: refactor cerber_log, include this status as a second parameter
cerber_log( 54 ); // TODO should be separate code?
$code = 'country_denied';
$msg = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' .
apply_filters( 'cerber_msg_denied', __( 'You are not allowed to register.', 'wp-cerber' ), 'register' );
}
if ( $code ) {
return array( $code, $msg );
}
return false;
}
/**
* Limit on user registrations per IP
*
* @return bool
*/
function crb_is_reg_limit_reached() {
if ( ! lab_lab() ) {
return false;
}
if ( ! crb_get_settings( 'reglimit_min' ) || ! crb_get_settings( 'reglimit_num' ) ) {
return false;
}
if ( crb_acl_is_white() ) {
return false;
}
$ip = cerber_get_remote_ip();
$stamp = absint( time() - 60 * crb_get_settings( 'reglimit_min' ) );
$count = cerber_db_get_var( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE ip = "' . $ip . '" AND activity = 2 AND stamp > ' . $stamp );
if ( $count >= crb_get_settings( 'reglimit_num' ) ) {
lab_save_push( $ip, 344, '' );
return true;
}
return false;
}
// Fires in register_new_user()
add_filter( 'registration_errors', 'cerber_pre_new_user', 10, 3 );
function cerber_pre_new_user( $errors, $sanitized_user_login, $user_email ) {
$prohibited = cerber_is_registration_prohibited( $sanitized_user_login );
if ( $prohibited ) {
return new WP_Error( $prohibited[0], $prohibited[1] );
}
return $errors;
}
// @since 5.3
// Fires in wp_insert_user()
add_filter( 'pre_user_login', function ( $sanitized_user_login ) {
if ( cerber_is_registration_prohibited( $sanitized_user_login ) ) {
return null;
}
return $sanitized_user_login;
}, 9999 );
// @since 7.2.7 for MU and BuddyPress
add_filter( 'wpmu_validate_user_signup', function ( $result ) {
$sanitized_user_login = sanitize_user( $result['user_name'], true );
if ( $check = cerber_is_registration_prohibited( $sanitized_user_login ) ) {
$result['errors'] = new WP_Error( 'user_name', $check[1] );
}
return $result;
}, 9999 );
// Filter out prohibited usernames
add_filter( 'illegal_user_logins', function () {
return (array) crb_get_settings( 'prohibited' );
}, 9999 );
add_filter( 'option_users_can_register', function ( $value ) {
//if ( ! cerber_is_allowed() || !cerber_geo_allowed( 'geo_register' )) {
if ( ! cerber_is_allowed() || crb_is_reg_limit_reached() ) {
return false;
}
return $value;
}, 9999 );
// Lost password form --------------------------------------------------------------------
/**
* Validate reCAPTCHA for the WordPress lost password form
*/
add_action( 'login_form_' . 'lostpassword', 'cerber_lost_captcha' );
function cerber_lost_captcha() {
global $wp_cerber, $cerber_lost;
if ( ! $wp_cerber->reCaptchaValidate() ) {
$_POST['user_login'] = null; // workaround due to lack of any way to control lost password form
$cerber_lost = '<strong>' . __( 'ERROR:', 'wp-cerber' ) . ' </strong>' . $wp_cerber->reCaptchaMsg('lostpassword');
}
}
/**
* Display message on the WordPress lost password form screen
*/
add_action( 'lostpassword_form', 'cerber_lost_show_msg' );
function cerber_lost_show_msg() {
global $cerber_lost;
if ( ! $cerber_lost ) {
return;
}
?>
<script type="text/javascript">
//document.getElementById('login_error').style.visibility = "hidden";
document.getElementById('login_error').innerHTML = "<?php echo $cerber_lost; ?>";
</script>
<?php
}
// Comments (commenting) section ----------------------------------------------------------
/**
* If a comment must be marked as spam
*
*/
add_filter( 'pre_comment_approved', function ( $approved, $commentdata ) {
if ( 1 == crb_get_settings( 'spamcomm' ) && ! cerber_is_comment_allowed() ) {
$approved = 'spam';
}
return $approved;
}, 10, 2 );
/**
* If a comment must be denied
*
*/
add_action( 'pre_comment_on_post', function ( $comment_post_ID ) {
global $cerber_status;
$deny = false;
if ( 1 != crb_get_settings( 'spamcomm' ) && ! cerber_is_comment_allowed() ) {
$deny = true;
}
elseif ( ! cerber_geo_allowed( 'geo_comment' ) ) {
$cerber_status = 16;
cerber_log(19);
$deny = true;
}
if ( $deny ) {
setcookie( 'cerber-post-id', $comment_post_ID, time() + 60, '/' );
$comments = get_comments( array( 'number' => '1', 'post_id' => $comment_post_ID ) );
if ( $comments ) {
$loc = get_comment_link( $comments[0]->comment_ID );
} else {
$loc = get_permalink( $comment_post_ID ) . '#cerber-recaptcha-msg';
}
wp_safe_redirect( $loc );
exit;
}
} );
/**
* If submit comments via REST API is not allowed
*
*/
add_filter( 'rest_allow_anonymous_comments', function ( $allowed, $request ) {
global $wp_cerber, $cerber_status;
if ( ! cerber_is_allowed() ) {
$allowed = false;
}
if ( ! cerber_geo_allowed( 'geo_comment' ) ) {
ceber_log(19);
$cerber_status = 16;
$allowed = false;
}
elseif ( lab_is_blocked( $wp_cerber->getRemoteIp() ) ) {
$allowed = false;
}
return $allowed;
}, 10, 2 );
/**
* Check if a submitted comment is allowed
*
* @return bool
*/
function cerber_is_comment_allowed(){
global $wp_cerber;
if (is_admin()) return true;
$deny = null;
if ( ! cerber_is_allowed() ) {
$deny = 19;
}
elseif ( cerber_is_bot('botscomm') ) {
$remain = cerber_get_remain_count( null, true, array( 16 ), 3, 60 );
if ($remain < 1) cerber_block_add( null, 706, '', 60 );
$deny = 16;
}
elseif ( ! $wp_cerber->reCaptchaValidate( 'comment' , true ) ) {
$deny = 16;
}
elseif ( lab_is_blocked( $wp_cerber->getRemoteIp() ) ) {
$deny = 19;
}
if ( $deny ) {
cerber_log( $deny );
$ret = false;
}
else {
$ret = true;
}
return $ret;
}
/**
* Showing reCAPTCHA widget.
* Displaying error message on the comment form for a human.
*
*/
add_filter( 'comment_form_submit_field', function ( $value ) {
global $wp_cerber, $post;
if ( ! empty( $_COOKIE["cerber-post-id"] ) && absint( $_COOKIE["cerber-post-id"] ) == $post->ID ) {
//echo '<div id="cerber-recaptcha-msg">' . __( 'ERROR:', 'wp-cerber' ) . ' ' . $wp_cerber->reCaptchaMsg( 'comment' ) . '</div>';
echo '<div id="cerber-recaptcha-msg">' . __( 'ERROR:', 'wp-cerber' ) . ' ' . __('Sorry, human verification failed.') . '</div>';
echo '<script type="text/javascript">document.cookie = "cerber-post-id=0;path=/";</script>';
}
$au = $wp_cerber->getSettings( 'recapcomauth' );
if ( ! $au || ( $au && ! is_user_logged_in() ) ) {
$wp_cerber->reCaptcha( 'widget', 'recapcom' );
}
return $value;
} );
// Messages ----------------------------------------------------------------------
/**
* Replace ANY system messages or add notify message above login form if IP is not allowed (blocked or locked out)
*/
add_filter( 'login_errors', 'cerber_login_form_msg' ); // hook on POST if credentials was wrong
function cerber_login_form_msg( $errors ) {
global $error, $wp_cerber;
if ( cerber_can_msg() ) {
if ( ! cerber_is_allowed() ) {
$errors = $wp_cerber->getErrorMsg();
}
elseif ( ! $error && ( $msg = $wp_cerber->getRemainMsg() ) ) {
$errors .= '<p>' . $msg;
}
}
return $errors;
}
add_filter( 'shake_error_codes', 'cerber_login_failure_shake' ); // Shake it, baby!
function cerber_login_failure_shake( $shake_error_codes ) {
$shake_error_codes[] = 'cerber_wp_error';
return $shake_error_codes;
}
/*
Replace default login/logout URL with Custom login page URL
*/
add_filter( 'site_url', 'cerber_login_logout', 9999, 4 );
add_filter( 'network_site_url', 'cerber_login_logout', 9999, 3 );
function cerber_login_logout( $url, $path, $scheme, $blog_id = 0 ) { // $blog_id only for 'site_url'
//global $wp_cerber;
//if ( $login_path = $wp_cerber->getSettings( 'loginpath' ) ) {
if ( $login_path = crb_get_settings( 'loginpath' ) ) {
$url = str_replace( WP_LOGIN_SCRIPT, $login_path . '/', $url );
}
return $url;
}
/*
Replace default logout redirect URL with Custom login page URL
*/
add_filter( 'wp_redirect', 'cerber_login_redirect', 9999, 2 );
function cerber_login_redirect( $location, $status ) {
global $wp_cerber;
//if ( ( $path = $wp_cerber->getSettings( 'loginpath' ) ) && ( 0 === strpos( $location, WP_LOGIN_SCRIPT . '?' ) ) ) {
if ( ( $path = crb_get_settings( 'loginpath' ) ) && ( 0 === strpos( $location, WP_LOGIN_SCRIPT . '?' ) ) ) {
$loc = explode( '?', $location );
$location = cerber_get_home_url() . '/' . $path . '/?' . $loc[1];
}
return $location;
}
// Access control ========================================================================================
add_action( 'init', function () {
if ( crb_get_settings( 'adminphp' ) && ! is_user_logged_in() ) {
define( 'CONCATENATE_SCRIPTS', false );
}
if ( ! is_admin()
&& ! cerber_is_wp_cron() ) {
cerber_access_control();
cerber_auth_access();
}
cerber_post_control();
}, 0 );
/**
* Restrict access to some vital parts of WP
*
*/
function cerber_access_control() {
global $wp_cerber, $cerber_status;
if ( crb_acl_is_white() ) {
return;
}
$wp_cerber = get_wp_cerber();
if ( $wp_cerber->isURIProhibited() ) {
cerber_404_page();
}
$opt = crb_get_settings();
// REST API
if ( $wp_cerber->isDeny() ) {
cerber_block_rest_api();
}
elseif ( cerber_is_rest_url() ) {
$rest_allowed = true;
/*if ( ! empty( $opt['norest'] ) ) {
$rest_allowed = false;
if ( $opt['restauth'] && is_user_logged_in() ) {
$rest_allowed = true;
}
elseif ( cerber_is_route_allowed() ) {
$rest_allowed = true;
}
}
if ( $rest_allowed && cerber_is_route_blocked() ) {
$rest_allowed = false;
}*/
if ( ! cerber_is_rest_permitted() ) {
$rest_allowed = false;
}
if ( $rest_allowed && ! cerber_geo_allowed( 'geo_restapi' ) ) {
$rest_allowed = false;
$cerber_status = 16;
}
if ( ! $rest_allowed ) {
cerber_block_rest_api();
}
}
// Some XML-RPC stuff
if ( $wp_cerber->isDeny() || ! empty( $opt['xmlrpc'] ) ) {
add_filter( 'xmlrpc_enabled', '__return_false' );
add_filter( 'pings_open', '__return_false' );
add_filter( 'bloginfo_url', 'cerber_pingback_url', 10, 2 );
remove_action( 'wp_head', 'rsd_link', 10 );
remove_action( 'wp_head', 'wlwmanifest_link', 10 );
}
// Feeds
if ( $wp_cerber->isDeny() || ! empty( $opt['nofeeds'] ) ) {
remove_action( 'wp_head', 'feed_links', 2 );
remove_action( 'wp_head', 'feed_links_extra', 3 );
remove_action( 'do_feed_rdf', 'do_feed_rdf', 10 );
remove_action( 'do_feed_rss', 'do_feed_rss', 10 );
remove_action( 'do_feed_rss2', 'do_feed_rss2', 10 );
remove_action( 'do_feed_atom', 'do_feed_atom', 10 );
remove_action( 'do_pings', 'do_all_pings', 10 );
add_action( 'do_feed_rdf', 'cerber_404_page', 1 );
add_action( 'do_feed_rss', 'cerber_404_page', 1 );
add_action( 'do_feed_rss2', 'cerber_404_page', 1 );
add_action( 'do_feed_atom', 'cerber_404_page', 1 );
add_action( 'do_feed_rss2_comments', 'cerber_404_page', 1 );
add_action( 'do_feed_atom_comments', 'cerber_404_page', 1 );
}
}
function cerber_auth_access() {
$opt = crb_get_settings();
if ( $opt['authonlyacl']
&& crb_acl_is_white() ) {
return;
}
if ( $opt['authonly']
&& ! is_user_logged_in()
&& cerber_auth_required( $opt['authonlyredir'] ) ) {
if ( $opt['authonlyredir'] ) {
$redirect = ( strpos( $_SERVER['REQUEST_URI'], '/options.php' ) && wp_get_referer() ) ? wp_get_referer() : set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
wp_redirect( add_query_arg( 'redirect_to', $redirect, $opt['authonlyredir'] ) );
exit;
}
auth_redirect();
}
}
/**
* Antispam & Antibot for forms
*
*/
function cerber_post_control() {
global $cerber_status;
if ( ! cerber_is_http_post() || crb_acl_is_white() ) {
return;
}
if ( ! cerber_antibot_enabled( 'botsany' ) && ! cerber_geo_rules( 'geo_submit' ) ) {
return;
}
// Exceptions -----------------------------------------------------------------------
if ( cerber_is_antibot_exception() ) {
return;
}
// Let's make the checks
$deny = false;
if ( ! cerber_is_allowed() ) {
$deny = true;
cerber_log( 18 );
}
elseif ( cerber_is_bot( 'botsany' ) ) {
$deny = true;
cerber_log( 17 );
}
elseif ( ! cerber_geo_allowed( 'geo_submit' ) ) {
$deny = true;
$cerber_status = 16; // TODO: refactor cerber_log, include this status as a second parameter
cerber_log( 18 );
}
elseif ( lab_is_blocked( null, true ) ) {
$deny = true;
$cerber_status = 18;
cerber_log( 18 );
}
if ( $deny ) {
cerber_forbidden_page();
}
}
/**
* Exception for POST request control
*
* @return bool
*/
function cerber_is_antibot_exception(){
if ( cerber_is_wp_cron() ) {
return true;
}
// Admin || AJAX requests by unauthorized users
if ( is_admin() ) {
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
if (is_user_logged_in()) {
return true;
}
}
else {
return true;
}
}
// Standard WordPress Comments
if ( 0 === strpos( trim( $_SERVER['REQUEST_URI'], '/' ), 'wp-comments-post.php' ) ) {
return true;
}
// XML-RPC
if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
return true;
}
// Trackback
if ( is_trackback() ) {
return true;
}
// Login page
if ( cerber_is_login_request() ) {
return true;
}
// Cloud Scanner
if ( cerber_is_cloud_request() ) {
return true;
}
if ( nexus_is_valid_request() ) {
return true;
}
// REST API (except Contact Form 7 submission)
if ( cerber_is_rest_url() ) {
if ( false === strpos( $_SERVER['REQUEST_URI'], 'contact-form-7' ) ) {
return true;
}
}
if ( class_exists( 'WooCommerce' ) ) {
if ( cerber_is_permalink_enabled() ) {
//if ( 0 === strpos( cerber_get_site_root() . cerber_purify_uri(), get_home_url() . '/wc-api/' ) ) {
//if ( 0 === strpos( CRB_Request::full_url(), cerber_get_home_url() . '/wc-api/' ) ) {
if ( CRB_Request::is_url_start_with( cerber_get_home_url() . '/wc-api/' ) ) {
return true;
}
}
elseif ( ! empty( $_GET['wc-api'] ) ) {
if ( cerber_check_remote_domain( array( '*.paypal.com', '*.stripe.com' ) ) ) {
return true;
}
}
}
return false;
}
/**
* What antibot mode must be used.
*
* @return int 1 = Cookies + Fields, 2 = Cookies only
*/
function cerber_antibot_mode() {
global $wp;
//static $list;
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
if ( crb_get_settings( 'botssafe' ) ) {
return 2;
}
if ( ! empty( $_POST['action'] ) ) {
if ( $_POST['action'] == 'heartbeat' ) { // WP heartbeat
//$nonce_state = wp_verify_nonce( $_POST['_nonce'], 'heartbeat-nonce' );
return 2;
}
}
}
if ( cerber_get_uri_script() ) {
return 1;
}
// Check for third party exceptions
if ( class_exists( 'WooCommerce' ) ) {
if ( ! empty( $_GET['wc-ajax'] ) &&
//$_GET['wc-ajax'] == 'get_refreshed_fragments' &&
count( $_GET ) == 1 &&
empty( $_POST )
) {
return 2;
}
if ( cerber_is_permalink_enabled() ) {
//if ( function_exists( 'wc_get_page_id' ) && 0 === strpos( cerber_get_site_root() . cerber_purify_uri(), get_permalink( wc_get_page_id( 'checkout' ) ) ) ) {
if ( function_exists( 'wc_get_page_id' ) && CRB_Request::is_url_start_with( get_permalink( wc_get_page_id( 'checkout' ) ) ) ) {
return 2;
}
}
else {
if ( ! empty( $_GET['order-received'] ) && ! empty( $_GET['key'] ) ) {
return 2;
}
}
}
if ( class_exists( 'GFForms' ) ) {
if ( count( $_GET ) == 2 &&
! empty( $_GET['gf_page'] ) &&
! empty( $_GET['id'] ) &&
is_user_logged_in()
) {
return 2;
}
}
return 1;
}
/*
* Disable pingback URL (hide from HEAD)
*/
function cerber_pingback_url( $output, $show ) {
if ( $show == 'pingback_url' ) {
$output = '';
}
return $output;
}
/**
* Disable REST API
*
*/
function cerber_block_rest_api() {
// OLD WP
add_filter( 'json_enabled', '__return_false' );
add_filter( 'json_jsonp_enabled', '__return_false' );
// WP 4.4, deprecated since 4.7
if ( version_compare( cerber_get_wp_version(), '4.7', '<' ) ) {
add_filter( 'rest_enabled', '__return_false', 9999 );
}
// WP 4.7
add_filter( 'rest_jsonp_enabled', '__return_false' );
// Links
remove_action( 'wp_head', 'rest_output_link_wp_head', 10 );
remove_action( 'template_redirect', 'rest_output_link_header', 11 );
// Default REST API hooks from default-filters.php
remove_action( 'init', 'rest_api_init' );
remove_action( 'rest_api_init', 'rest_api_default_filters', 10 );
remove_action( 'rest_api_init', 'register_initial_settings', 10 );
remove_action( 'rest_api_init', 'create_initial_rest_routes', 99 );
remove_action( 'parse_request', 'rest_api_loaded' );
if ( cerber_is_rest_url() ) {
cerber_log( 70 );
cerber_forbidden_page();
}
}
/*
* Redirection control: standard admin/login redirections
*
*/
add_filter( 'wp_redirect', function ( $location ) {
global $current_user;
if ( ( ! $current_user || $current_user->ID == 0 ) && cerber_no_redirect() ) {
//$str = urlencode( '/wp-admin/' );
$rdr = explode( 'redirect_to=', $location );
/*if ( isset( $rdr[1] ) && strpos( $rdr[1], $str ) ) {
cerber_404_page();
}*/
if ( isset( $rdr[1] ) ) {
$redirect_to = urldecode( $rdr[1] ); // a normal
$redirect_to = urldecode( $redirect_to ); // @since 8.1 - may be twice encoded to bypass
if ( strpos( $redirect_to, '/wp-admin/' ) ) {
cerber_404_page();
}
}
}
return $location;
}, 0 );
/**
* @since 7.0
*/
function cerber_no_redirect() {
if ( crb_get_settings( 'noredirect' ) && !cerber_check_groove_x()) {
return true;
}
return false;
}
/*
* Stop user enumeration
*
*/
add_action( 'template_redirect', function () {
if ( crb_get_settings( 'stopenum' ) ) {
if ( ! $a = crb_array_get( $_GET, 'author' ) ) {
if ( ! $a = crb_array_get( $_POST, 'author' ) ) { // @since 8.1
return;
}
}
if ( is_numeric( trim( $a ) ) && ! is_admin() ) {
cerber_404_page();
}
}
}, 0 );
/*
if ( $wp_cerber->getSettings( 'hashauthor' ) ) {
add_filter( 'request',
function ( $vars ) {
if (isset($vars['author_name']) && !is_admin()) {
$vars['author_name'] = '><';
}
return $vars;
} );
}
*/
/*
Can login form message be shown?
*/
function cerber_can_msg() {
if ( ! isset( $_REQUEST['action'] ) ) {
return true;
}
if ( $_REQUEST['action'] == 'login' ) {
return true;
}
return false;
//if ( !in_array( $action, array( 'postpass', 'logout', 'lostpassword', 'retrievepassword', 'resetpass', 'rp', 'register', 'login' );
}
// Cookies ---------------------------------------------------------------------------------
/*
Mark user with Cerber Groove
@since 1.3
*/
add_action( 'auth_cookie_valid', 'cerber_cookie_one', 10, 2 );
function cerber_cookie_one( $cookie_elements = null, $user = null ) {
if ( ! $user ) {
$user = wp_get_current_user();
}
// Mark user with Cerber Groove
$expire = time() + apply_filters( 'auth_cookie_expiration', 14 * 24 * 3600, $user->ID, true ) + ( 24 * 3600 );
cerber_set_groove( $expire );
}
/*
Mark switched user with Cerber Groove
@since 1.6
*/
add_action( 'set_logged_in_cookie', 'cerber_cookie2', 10, 5 );
function cerber_cookie2( $logged_in_cookie, $expire, $expiration, $user_id, $logged_in ) {
cerber_set_groove( $expire );
}
/*
Track BAD cookies with non-existence user or bad password (hash)
*/
add_action( 'auth_cookie_bad_username', 'cerber_cookie_bad' );
add_action( 'auth_cookie_bad_hash', 'cerber_cookie_bad' );
function cerber_cookie_bad( $cookie_elements ) {
cerber_login_failed( $cookie_elements['username'] );
}
/**
* Is bot detection engine enabled in a given rule_id
*
* @param $location string|array ID of the location
*
* @return bool true if enabled
*/
function cerber_antibot_enabled( $location ) {
if ( crb_get_settings( 'botsnoauth' ) && is_user_logged_in() ) {
return false;
}
if ( is_array( $location ) ) {
foreach ( $location as $loc ) {
if ( crb_get_settings( $loc ) ) {
return true;
}
}
}
else {
if ( crb_get_settings( $location ) ) {
return true;
}
}
return false;
}
/**
* Print out the antibot/antispam jQuery code
*
* @param $location string|array Location (setting)
*/
function cerber_antibot_code($location) {
if ( ! cerber_antibot_enabled( $location ) ) {
return;
}
$values = cerber_antibot_gene();
if ( empty( $values ) || !is_array( $values ) ) {
return;
}
?>
<script type="text/javascript">
jQuery(document).ready(function ($) {
//$( document ).ajaxStart(function() {
//});
<?php // Append form fields directly to the all forms ?>
for (var i = 0; i < document.forms.length; ++i) {
var form = document.forms[i];
<?php
foreach ( $values[0] as $value ) {
echo 'if ($(form).attr("method") != "get") { $(form).append(\'<input type="hidden" name="' . $value[0] . '" value="' . $value[1] . '" />\'); }'."\n";
}
?>
}
<?php // Ordinary submit ?>
$(document).on('submit', 'form', function () {
<?php
foreach ( $values[0] as $value ) {
echo 'if ($(this).attr("method") != "get") { $(this).append(\'<input type="hidden" name="' . $value[0] . '" value="' . $value[1] . '" />\'); }'."\n";
}
?>
return true;
});
<?php // Pure AJAX submit with two different types of form data (object and string) ?>
jQuery.ajaxSetup({
beforeSend: function (e, data) {
//console.log(Object.getOwnPropertyNames(data).sort());
//console.log(data.type);
if (data.type !== 'POST') return;
if (typeof data.data === 'object' && data.data !== null) {
<?php
foreach ( $values[0] as $value ) {
echo 'data.data.append("' . $value[0] . '", "' . $value[1] . '");'."\n";
}
?>
}
else {
data.data = data.data + '<?php
foreach ( $values[0] as $value ) {
echo '&' . $value[0] . '=' . $value[1];
}
?>';
}
}
});
});
</script>
<?php
}
/**
* Generates and saves antibot markers
*
* @return array|bool
*/
function cerber_antibot_gene($recreate = false) {
if ( !crb_get_settings('botsany') && !crb_get_settings('botscomm') && !crb_get_settings('botsreg') ) {
return false;
}
$ret = array();
if (!$recreate) {
$ret = cerber_get_site_option( 'cerber-antibot' );
}
if ( $recreate || !$ret ) {
$ret = array();
$max = rand( 2, 4 );
for ( $i = 1; $i <= $max; $i ++ ) {
$length = rand( 6, 16 );
$string1 = str_shuffle( 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-' );
$string2 = str_shuffle( '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.@*_[]' );
$ret[0][] = array( substr( $string1, 0, $length ), substr( $string2, 0, $length ) );
}
$max = rand( 2, 4 );
for ( $i = 1; $i <= $max; $i ++ ) {
$length = rand( 6, 16 );
$string1 = str_shuffle( 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-' );
$string2 = str_shuffle( '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.@*_[]' );
$ret[1][] = array( substr( $string1, 0, $length ), substr( $string2, 0, $length ) );
}
update_site_option( 'cerber-antibot', $ret );
}
return $ret;
}
/**
* Is a POST request (a form) submitted by a bot?
*
* @param $location string identificator of a place where we are check for a bot
*
* @return bool
*/
function cerber_is_bot( $location = '' ) {
global $cerber_status;
static $ret = null;
$remote_ip = cerber_get_remote_ip();
if ( $remote_ip == '127.0.0.1' || $remote_ip == '::1' ) {
return false; // v. 7.8.5
}
if ( isset( $ret ) ) {
return $ret;
}
if ( ! $location || ! cerber_is_http_post() || cerber_is_wp_cron() ) {
$ret = false;
return $ret;
}
// Admin || AJAX requests by unauthorized users
if ( is_admin() ) {
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
if ( is_user_logged_in() ) {
$ret = false;
}
elseif ( ! empty( $_POST['action'] ) ) {
if ( $_POST['action'] == 'heartbeat' ) { // WP heartbeat
//$nonce_state = wp_verify_nonce( $_POST['_nonce'], 'heartbeat-nonce' );
$ret = false;
}
}
}
else {
$ret = false;
}
}
if ($ret !== null) {
return $ret;
}
if ( ! cerber_antibot_enabled( $location ) ) {
$ret = false;
return $ret;
}
// Antibot whitelist
if ( ( $list = crb_get_settings( 'botswhite' ) ) && is_array( $list ) ) {
foreach ( $list as $item ) {
if ( substr( $item, 0, 1 ) == '{' && substr( $item, - 1 ) == '}' ) {
$pattern = '/' . substr( $item, 1, - 1 ) . '/i';
if ( @preg_match( $pattern, '/' . trim( $_SERVER['REQUEST_URI'], '/' ) ) ) {
$ret = false;
return $ret;
}
}
elseif ( false !== strpos( '/' . trim( $_SERVER['REQUEST_URI'], '/' ), $item ) ) {
$ret = false;
return $ret;
}
}
}
$antibot = cerber_antibot_gene();
$ret = false;
if ( ! empty( $antibot ) ) {
$mode = cerber_antibot_mode();
if ( $mode == 1 ) {
foreach ( $antibot[0] as $fields ) {
if ( empty( $_POST[ $fields[0] ] ) || $_POST[ $fields[0] ] != $fields[1] ) {
$ret = true;
break;
}
}
}
if ( ! $ret ) {
foreach ( $antibot[1] as $fields ) {
if ( empty( $_COOKIE[ $fields[0] ] ) || $_COOKIE[ $fields[0] ] != $fields[1] ) {
$ret = true;
break;
}
}
}
if ( $ret ) {
$cerber_status = 11;
lab_save_push( $remote_ip, 333, '' );
}
}
return $ret;
}
function cerber_geo_allowed( $rule_id = '' ) {
if ( ! $rule_id || cerber_is_wp_cron() || ! lab_lab() ) {
return true;
}
if ( crb_acl_is_white() ) {
return true;
}
$rule = cerber_geo_rules( $rule_id );
$wp_cerber = get_wp_cerber();
if ( $rule && $country = lab_get_country( $wp_cerber->getRemoteIp(), false ) ) {
if ( in_array( $country, $rule['list'] ) ) {
if ( $rule['type'] == 'W' ) {
return true;
}
return false;
}
if ( $rule['type'] == 'W' ) {
return false;
}
return true;
}
return true;
}
/**
* Retrieve and return GEO rule(s) from the DB
*
* @param string $rule_id Slug of a rule
*
* @return bool|array If a rule exists return array of countries
*/
function cerber_geo_rules( $rule_id = '' ) {
global $wpdb;
if (is_multisite()) {
//$geo = $wpdb->get_var( 'SELECT meta_value FROM ' . $wpdb->sitemeta . ' WHERE meta_key = "geo_rule_set"' );
$geo = cerber_db_get_var( 'SELECT meta_value FROM ' . $wpdb->sitemeta . ' WHERE meta_key = "geo_rule_set"' );
}
else {
//$geo = $wpdb->get_var( 'SELECT option_value FROM ' . $wpdb->options . ' WHERE option_name = "geo_rule_set"' );
$geo = cerber_db_get_var( 'SELECT option_value FROM ' . $wpdb->options . ' WHERE option_name = "geo_rule_set"' );
}
if ( $geo ) {
$rules = unserialize( $geo );
if ( $rule_id ) {
if ( ! empty( $rules[ $rule_id ] ) ) {
$ret = $rules[ $rule_id ];
}
else {
$ret = false;
}
}
else {
$ret = $rules;
}
}
else {
$ret = false;
}
return $ret;
}
/**
* Set user session expiration
*
*/
add_filter( 'auth_cookie_expiration', function ( $expire ) {
$time = crb_get_settings( 'auth_expire' );
if ( $time ) {
$expire = 60 * $time;
}
return $expire;
} );
// Track various activity -------------------------------------------------------------------------
add_action( 'wp_login', function ( $login, $user ) {
global $wp_cerber_user_id;
if ( ! empty( $_POST['log'] ) ) { // default WP form
$user_login = htmlspecialchars( $_POST['log'] );
}
else {
$user_login = $login;
}
$wp_cerber_user_id = $user->ID;
cerber_log( 5, $user_login, $user->ID );
}, 10, 2 );
/**
* Catching some cases of authentication without using login form or not a default user login process
*/
add_action( 'set_auth_cookie', function () {
add_action( 'shutdown', function () { // deferred to allow the possible 'wp_login' action be logged first
if ($user_id = get_current_user_id()) {
cerber_log( 5, '', $user_id );
}
} );
} );
/*add_action( 'wp_logout', function() {
global $user_ID;
if ( ! $user_ID ) {
$user = wp_get_current_user();
$user_ID = $user->ID;
}
cerber_log( 6, '', $user_ID );
});*/
add_action( 'clear_auth_cookie', function () {
$uid = get_current_user_id();
if ( $uid ) {
cerber_log( 6, '', $uid );
}
setcookie( 'cerber_nexus_id', 0, time(), '/' );
} );
//add_action( 'lostpassword_post', 'cerber_password_post' );
add_action( 'retrieve_password', function ( $user_login ) {
cerber_log( 21, $user_login );
} );
add_action( 'password_reset', 'crb_pass_reset' );
add_action( 'crb_after_reset', 'crb_pass_reset', 10, 2);
function crb_pass_reset( $user, $user_id = null) {
if ( ! $user && $user_id ) {
$user = get_user_by( 'id', $user_id );
}
if ( ! $user ) {
return;
}
cerber_log( 20, $user->user_login, $user->ID );
}
// Fires in wp_insert_user()
add_action( 'user_register', function ( $user_id ) { // @since 5.6
$cid = get_current_user_id();
if ($user = get_user_by( 'ID', $user_id )) {
if ( $cid && $cid != $user_id ) {
$ac = 1;
}
else {
$ac = 2;
}
cerber_log( $ac, $user->user_login, $user_id );
crb_log_user_ip( $user_id, $cid );
}
});
// Fires after a new user has been created in WP dashboard.
add_action( 'edit_user_created_user', function ( $user_id, $notify = null ) {
if ( $user_id && $user = get_user_by( 'ID', $user_id ) ) {
cerber_log( 1, $user->user_login, $user_id );
crb_log_user_ip( $user_id );
}
}, 10, 2 );
// Log IP address of user registration independently
function crb_log_user_ip( $user_id, $by_user = null ) {
global $wp_cerber;
if ( ! $user_id ) {
return;
}
if ( ! $by_user ) {
$by_user = get_current_user_id();
}
add_user_meta( $user_id, '_crb_reg_', array( 'IP' => $wp_cerber->getRemoteIp(), 'user' => $by_user ) );
}
// Lockouts routines ---------------------------------------------------------------------
/**
* Lock out IP address if it is an alien IP only (browser does not have valid Cerber groove)
*
* @param $ip string IP address to block
* @param integer $reason_id ID of reason of blocking
* @param string $details Reason of blocking
* @param null $duration Duration of blocking
*
* @return bool|false|int
*/
function cerber_soft_block_add( $ip, $reason_id, $details = '', $duration = null ) {
if ( cerber_check_groove() ) {
return false;
}
return cerber_block_add( $ip, $reason_id, $details, $duration );
}
/**
* Lock out IP address
*
* @param $ip string IP address to block
* @param integer $reason_id ID of reason of blocking
* @param string $details Reason of blocking
* @param int $duration Duration of blocking
*
* @return bool|false|int
*/
function cerber_block_add( $ip = '', $reason_id = 1, $details = '', $duration = null ) {
global $cerber_blocked;
if ( cerber_is_cloud_request() ) {
return false;
}
$wp_cerber = get_wp_cerber();
//$wp_cerber->setProcessed();
if ( empty( $ip ) || ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
$ip = $wp_cerber->getRemoteIp();
}
if ( cerber_get_block( $ip ) ) {
return false;
}
if ( cerber_acl_check( $ip ) ) {
return false;
}
$ip_address = $ip;
lab_save_push( $ip, $reason_id, $details );
if ( $wp_cerber->getSettings( 'subnet' ) ) {
$ip = cerber_get_subnet( $ip );
$activity = 11;
}
else {
$activity = 10;
}
/*if ( $wpdb->get_var( $wpdb->prepare( 'SELECT count(ip) FROM ' . CERBER_BLOCKS_TABLE . ' WHERE ip = %s', $ip ) ) ) {
return false;
}*/
$reason = cerber_get_reason( $reason_id );
if ( $details ) {
$reason .= ': <b>' . $details . '</b>';
}
if ( ! $duration ) {
$duration = cerber_calc_duration( $ip );
}
$until = time() + $duration;
//$result = $wpdb->query($wpdb->prepare('INSERT INTO '. CERBER_BLOCKS_TABLE . ' (ip,block_until,reason) VALUES (%s,%d,%s)',$ip,$until,$reason));
/*
$result = $wpdb->insert( CERBER_BLOCKS_TABLE, array(
'ip' => $ip,
'block_until' => $until,
'reason' => $reason,
'reason_id' => absint( $reason_id )
), array( '%s', '%d', '%s' ) );*/
$reason = cerber_real_escape( $reason );
$result = cerber_db_query( 'INSERT INTO ' . CERBER_BLOCKS_TABLE . ' (ip,block_until,reason,reason_id) VALUES ("' . $ip . '",' . $until . ',"' . $reason . '",' . absint( $reason_id ) . ')' );
if ( $result ) {
$cerber_blocked = $reason_id;
cerber_log( $activity, null, null, $ip_address );
$wp_cerber->setLocked();
do_action( 'cerber_ip_locked', array( 'IP' => $ip_address, 'reason' => $reason ) );
$result = true;
}
else {
cerber_db_error_log();
$result = false;
}
if ( $wp_cerber->getSettings( 'notify' ) ) {
$count = cerber_blocked_num();
if ( $count > $wp_cerber->getSettings( 'above' ) ) {
cerber_send_email( 'lockout', '', $ip_address );
}
}
return $result;
}
/**
*
* Check if an IP address is currently blocked. With C subnet also.
*
* @param string $ip an IP address
*
* @return bool true if IP is locked out
*/
function cerber_block_check( $ip = '' ) {
// @since 4.8
if ( cerber_get_block( $ip ) ) {
return true;
}
return false;
}
/**
*
* Return the lockout row for an IP if it is blocked. With C subnet also.
*
* @param string $ip an IP address
*
* @return object|bool object if IP is locked out, false otherwise
*/
function cerber_get_block( $ip = '' ) {
global $wp_cerber;
if ( ! $ip ) {
$wp_cerber = get_wp_cerber();
$ip = $wp_cerber->getRemoteIp();
}
if ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
return false;
}
$where = ' WHERE ip = "' . $ip . '"';
if ( cerber_is_ipv4( $ip ) ) {
$subnet = cerber_get_subnet( $ip );
$where .= ' OR ip = "' . $subnet . '"';
}
/*if ( $ret = $wpdb->get_row( 'SELECT * FROM ' . CERBER_BLOCKS_TABLE . $where ) ) {
return $ret;
}*/
if ( $ret = cerber_db_get_row( 'SELECT * FROM ' . CERBER_BLOCKS_TABLE . $where, MYSQL_FETCH_OBJECT ) ) {
return $ret;
}
return false;
}
/**
* Return the number of currently locked out IPs
*
* @return int the number of currently locked out IPs
* @since 3.0
*/
function cerber_blocked_num() {
return absint( cerber_db_get_var( 'SELECT count(ip) FROM ' . CERBER_BLOCKS_TABLE ) );
}
/**
* Calculate duration for a lockout of an IP address based on settings
*
* @param string $ip
*
* @return integer Duration in seconds
*/
function cerber_calc_duration( $ip ) {
$range = time() - crb_get_settings( 'aglast' ) * 3600;
//$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 ) );
//$lockouts = $wpdb->get_var( 'SELECT COUNT(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE ip = "' . $ip . '" AND activity IN (10,11) AND stamp > ' . $range );
$lockouts = cerber_db_get_var( 'SELECT COUNT(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE ip = "' . $ip . '" AND activity IN (10,11) AND stamp > ' . $range );
if ( $lockouts >= crb_get_settings( 'aglocks' ) ) {
$ret = crb_get_settings( 'agperiod' ) * 3600;
}
else {
$ret = crb_get_settings( 'lockout' ) * 60;
}
$ret = absint( $ret );
if ( $ret < 60 ) {
$ret = 60;
}
return $ret;
}
/**
* Calculation of remaining attempts
*
* @param $ip string an IP address
* @param $check_acl bool if true will check the White IP ACL first
* @param $activity array List of activity IDs to calculate for
* @param $allowed int Allowed attempts within $period
* @param $period int Period for count attempts
*
* @return int Allowed attempts for present moment
*/
function cerber_get_remain_count( $ip = '', $check_acl = true, $activity = array( '7,51,52' ), $allowed = null, $period = null ) {
global $wpdb, $wp_cerber;
if ( ! $ip ) {
$ip = $wp_cerber->getRemoteIp();
}
else {
if ( ! $ip = filter_var( $ip, FILTER_VALIDATE_IP ) ) {
return 0;
}
}
if ( ! $allowed ) {
$allowed = absint( crb_get_settings( 'attempts' ) );
}
if ( $check_acl && crb_acl_is_white( $ip ) ) {
return $allowed; // whitelist = infinity attempts
}
if ( ! $period ) {
$period = absint( crb_get_settings( 'period' ) );
}
$range = time() - $period * 60;
$in = implode( ',', array_filter( array_map( 'absint', $activity ) ) );
$attempts = cerber_db_get_var( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE . ' WHERE ip = "' . $ip . '" AND activity IN (' . $in . ') AND stamp > ' . $range );
if ( ! $attempts ) {
return $allowed;
}
else {
$ret = $allowed - $attempts;
}
$ret = $ret < 0 ? 0 : $ret;
return $ret;
}
/**
* Is a given IP is allowed to do restricted things?
* Here Cerber makes its decision.
*
* @param $ip string IP address
* @param $allowed array A list of reason ids @since 7.5.2
* @param $ignore_citadel bool
*
* @return bool
*/
function cerber_is_allowed( $ip = '', $allowed = array(), $ignore_citadel = false ) {
if ( ! $ip ) {
//$wp_cerber = get_wp_cerber();
//$ip = $wp_cerber->getRemoteIp();
$ip = cerber_get_remote_ip();
}
elseif ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
return false;
}
// @since 7.5.2
$tag = cerber_acl_check( $ip );
if ( $tag == 'W' ) {
return true;
}
if ( $tag == 'B' ) {
return false;
}
// @since 4.7.9
if ( $b = cerber_get_block( $ip ) ) {
if ( empty( $allowed ) ) {
return false;
}
elseif ( ! in_array( $b->reason_id, $allowed ) ) {
return false;
}
}
/* @since 4.7.9
if ( cerber_block_check( $ip ) ) {
return false;
}*/
if ( ! $ignore_citadel && cerber_is_citadel() ) {
return false;
}
if ( lab_is_blocked( $ip, false ) ) {
return false;
}
return true;
}
/**
* Check if a given username is not permitted to log in or register
*
* @param $username string
*
* @return bool true if username is prohibited
*/
function cerber_is_prohibited( $username ) {
if ( ! $username ) {
return false;
}
if ( $list = (array) crb_get_settings( 'prohibited' ) ) {
foreach ( $list as $item ) {
if ( mb_substr( $item, 0, 1 ) == '/' && mb_substr( $item, - 1 ) == '/' ) {
$pattern = trim( $item, '/' );
if ( @mb_ereg_match( $pattern, $username, 'i' ) ) {
return true;
}
}
elseif ($username === $item){
return true;
}
}
}
return false;
}
// TODO: Merge with $wp_cerber->getStatus();
function cerber_get_status( $ip ) {
global $cerber_status;
if ( ! empty( $cerber_status ) ) {
return absint($cerber_status);
}
if ( cerber_block_check( $ip ) ) {
return 13;
}
$tag = cerber_acl_check( $ip );
if ( $tag == 'W' ) {
return 0;
}
if ( $tag == 'B' ) {
return 14;
}
if ( cerber_is_citadel() ) {
return 12;
}
if ( lab_is_blocked( $ip, false ) ) {
return 15;
}
return 0;
}
// Access lists (ACL) routines --------------------------------------------------------------------------------
// TODO: move to dashboard.php
/**
* Add IP to specified access list
*
* @param $ip string|array single IP address, string with IP network, range or associative range array
* @param $tag string 'B'|'W'
*
* @return bool|int|object Result of operation
*/
function cerber_acl_add( $ip, $tag, $comment = '') {
global $wpdb;
if ( is_string( $ip ) ) {
if ( ! cerber_is_ipv4( $ip ) ) {
$ip = cerber_short_ipv6( $ip );
}
if ( cerber_db_get_var( $wpdb->prepare( 'SELECT COUNT(ip) FROM ' . CERBER_ACL_TABLE . ' WHERE ip = %s', $ip ) ) ) {
return false; //__( 'Element is already in list', 'wp-cerber' );
}
$range = cerber_any2range( $ip );
if ( is_array( $range ) ) {
$begin = $range['begin'];
$end = $range['end'];
}
else {
if (cerber_is_ipv4($ip)) {
$begin = ip2long( $ip );
$end = ip2long( $ip );
}
else{
$begin = 0;
$end = 0;
}
}
$result = $wpdb->insert( CERBER_ACL_TABLE, array( 'ip' => $ip,
'ip_long_begin' => $begin,
'ip_long_end' => $end,
'tag' => $tag,
'comments' => $comment
), array( '%s', '%d', '%d', '%s', '%s' ) );
return $result;
}
elseif ( is_array( $ip ) ) {
$range = $ip['range'];
$begin = $ip['begin'];
$end = $ip['end'];
if ( cerber_db_get_var( $wpdb->prepare( 'SELECT COUNT(ip) FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin = %d AND ip_long_end = %d', $begin, $end ) ) ) {
return false;
}
$result = $wpdb->insert( CERBER_ACL_TABLE, array( 'ip' => $range,
'ip_long_begin' => $begin,
'ip_long_end' => $end,
'tag' => $tag,
'comments' => $comment
), array( '%s', '%d', '%d', '%s', '%s' ) );
return $result;
//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 ) );
}
return false;
}
// TODO: move to dashboard.php
function cerber_add_white( $ip, $comment = '' ) {
return cerber_acl_add( $ip, 'W', $comment );
}
// TODO: move to dashboard.php
function cerber_add_black( $ip, $comment = '') {
return cerber_acl_add( $ip, 'B', $comment );
}
// TODO: move to dashboard.php
function cerber_acl_remove( $ip ) {
global $wpdb;
if ( is_string( $ip ) ) {
return $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . CERBER_ACL_TABLE . ' WHERE ip = %s ', $ip ) );
} elseif ( is_array( $ip ) ) {
return $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin = %d AND ip_long_end = %d', $ip['begin'], $ip['end'] ) );
}
return false;
}
// TODO: move to dashboard.php
/**
* Can a given IP (user input) be added to the blacklist
*
* @param $ip
* @param string $list
*
* @return bool
*/
function cerber_can_be_listed( $ip, $list = 'B' ) {
if ( $list == 'B' ) {
if ( crb_acl_is_white( cerber_get_remote_ip() ) ) {
return true;
}
if ( filter_var( $ip, FILTER_VALIDATE_IP ) ) {
if ( cerber_is_myip( $ip ) ) {
return false;
}
}
$range = cerber_any2range( $ip );
if ( cerber_is_ip_in_range( $range ) ) {
return false;
}
return true;
}
return true;
}
/**
* Is an IP whitelisted?
*
* @param $ip string
*
* @return bool
*/
function crb_acl_is_white( $ip = null ){
if ( cerber_acl_check( $ip, 'W' ) ) {
return true;
}
return false;
}
/**
* Is an IP blacklisted?
*
* @param $ip string
*
* @return bool
*/
function crb_acl_is_black( $ip = '' ) {
$tag = cerber_acl_check( $ip );
if ( $tag === 'W' ) {
return false;
}
elseif ( $tag === 'B' ) {
return true;
}
return false;
}
/**
* Check ACLs for given IP. Some extra lines for performance reason.
*
* @param string $ip
* @param string $tag
*
* @return bool|string
*/
function cerber_acl_check( $ip = null, $tag = '' ) {
global $wp_cerber;
static $cache;
if ( ! $ip ) {
$wp_cerber = get_wp_cerber();
$ip = $wp_cerber->getRemoteIp();
//$ip = cerber_get_remote_ip();
}
$key = cerber_get_id_ip( $ip ) . (string)$tag;
if ( isset( $cache[ $key ] ) ) {
return $cache[ $key ];
}
if ( ! cerber_is_ipv4( $ip ) ) {
$ret = cerber_acl_checkV6( $ip, $tag );
$cache[ $key ] = $ret;
return $ret;
}
$long = ip2long( $ip );
if ( $tag ) {
if ( $tag !== 'W' && $tag !== 'B' ) {
$ret = false;
}
elseif ( cerber_db_get_var( 'SELECT ip FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin <= '.$long.' AND '.$long.' <= ip_long_end AND tag = "'.$tag.'" LIMIT 1' ) ) {
$ret = true;
}
else {
$ret = false;
}
$cache[ $key ] = $ret;
return $ret;
}
else {
// We use two queries because of possible overlapping an IP and its network
if ( $ret = cerber_db_get_var( 'SELECT tag FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin <= ' . $long . ' AND ' . $long . ' <= ip_long_end AND tag = "W" LIMIT 1' ) ) {
$cache[ $key ] = $ret;
return $ret;
}
if ( $ret = cerber_db_get_var( 'SELECT tag FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin <= ' . $long . ' AND ' . $long . ' <= ip_long_end AND tag = "B" LIMIT 1' ) ) {
$cache[ $key ] = $ret;
return $ret;
}
$cache[ $key ] = false;
return false;
}
}
/**
* IPv6 version of cerber_acl_check() without subnets and ranges
*
* @param null $ip
* @param string $tag
*
* @return bool|null|string
*/
function cerber_acl_checkV6( $ip = null, $tag = '' ) {
global $wp_cerber;
if ( ! $ip ) {
//$ip = $wp_cerber->getRemoteIp();
$ip = cerber_get_remote_ip();
}
elseif ( ! cerber_is_ip( $ip ) ) {
return false;
}
if ( $tag ) {
if ( $tag != 'W' && $tag != 'B' ) {
return false;
}
if ( cerber_db_get_var( 'SELECT count(ip) FROM ' . CERBER_ACL_TABLE . ' WHERE ip = "' . $ip . '" AND tag = "' . $tag . '"' ) ) {
return true;
}
return false;
}
else {
if ( $ret = cerber_db_get_var( 'SELECT tag FROM ' . CERBER_ACL_TABLE . ' WHERE ip = "' . $ip . '"' ) ) {
return $ret;
}
return false;
}
}
/*
* Logging directly to the file
*
* CERBER_FAIL_LOG optional, full path including filename to the log file
* CERBER_LOG_FACILITY optional, use to specify what type of program is logging the messages
*
* */
function cerber_file_log( $user_login, $ip ) {
if ( defined( 'CERBER_FAIL_LOG' ) ) {
if ( $log = @fopen( CERBER_FAIL_LOG, 'a' ) ) {
$pid = absint( @posix_getpid() );
@fwrite( $log, date( 'M j H:i:s ' ) . $_SERVER['SERVER_NAME'] . ' Cerber(' . $_SERVER['HTTP_HOST'] . ')[' . $pid . ']: Authentication failure for ' . $user_login . ' from ' . $ip . "\n" );
@fclose( $log );
}
} else {
@openlog( 'Cerber(' . $_SERVER['HTTP_HOST'] . ')', LOG_NDELAY | LOG_PID, defined( 'CERBER_LOG_FACILITY' ) ? CERBER_LOG_FACILITY : LOG_AUTH );
@syslog( LOG_NOTICE, 'Authentication failure for ' . $user_login . ' from ' . $ip );
@closelog();
}
}
/*
Return wildcard - string like subnet Class C
*/
function cerber_get_subnet( $ip ) {
return preg_replace( '/\.\d{1,3}$/', '.*', $ip );
}
/*
Check if given IP address or wildcard or CIDR is valid
*/
function cerber_is_ip_or_net( $ip ) {
if ( filter_var( $ip, FILTER_VALIDATE_IP ) ) {
return true;
}
// WILDCARD: 192.168.1.*
$ip = str_replace( '*', '0', $ip );
//if ( @inet_pton( $ip ) ) {
if ( filter_var( $ip, FILTER_VALIDATE_IP ) ) {
return true;
}
// CIDR: 192.168.1/24
if ( strpos( $ip, '/' ) ) {
$cidr = explode( '/', $ip );
$net = $cidr[0];
$mask = absint( $cidr[1] );
$dots = substr_count( $net, '.' );
if ( $dots < 3 ) {
if ( $dots == 1 ) {
$net .= '.0.0';
} elseif ( $dots == 2 ) {
$net .= '.0';
}
}
if ( ! cerber_is_ipv4( $net ) ) {
return false;
}
if ( ! is_numeric( $mask ) ) {
return false;
}
return true;
}
return false;
}
/**
* Tries to recognize single IP address or IP v4 range (with dash) in a given string.
*
* @param string $string String to recognize IP address in
*
* @return array|bool|string Return single IP address or wildcard or CIDR as a string, and IP range as an array.
*/
function cerber_parse_ip( $string = '' ) {
$string = trim( $string );
if ( cerber_is_ip_or_net( $string ) ) {
return $string;
}
$explode = explode( '-', $string );
if ( ! is_array( $explode ) || ! $explode ) {
return false;
}
$range = array();
$count = 0;
foreach ( $explode as $ip ) {
$ip = trim( $ip );
if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) ) {
$range[] = $ip;
$count ++;
if ( $count >= 2 ) {
break;
}
}
}
if ( count( $range ) < 2 ) {
return false;
}
if ( ip2long( $range[1] ) <= ip2long( $range[0] ) ) {
return false;
}
return array(
'range' => $range[0] . ' - ' . $range[1],
'begin_ip' => $range[0],
'end_ip' => $range[1],
'begin' => ip2long( $range[0] ),
'end' => ip2long( $range[1] ),
);
}
/**
* Convert a network wildcard string like x.x.x.* to an IP v4 range
*
* @param $wildcard string
*
* @return array|bool|string False if no wildcard found, otherwise result of cerber_parse_ip()
*/
function cerber_wildcard2range( $wildcard = '' ) {
$begin = str_replace( '*', '0', $wildcard );
$end = str_replace( '*', '255', $wildcard );
if ( ! cerber_is_ipv4( $begin ) ) {
return false;
}
if ( ! cerber_is_ipv4( $end ) ) {
return false;
}
return cerber_parse_ip( $begin . ' - ' . $end );
}
/**
* Convert a CIDR to an IP v4 range
*
* @param $cidr string
*
* @return array|bool|string
*/
function cerber_cidr2range( $cidr = '' ) {
if ( ! strpos( $cidr, '/' ) ) {
return false;
}
$cidr = explode( '/', $cidr );
$net = $cidr[0];
$mask = absint( $cidr[1] );
$dots = substr_count( $net, '.' );
if ( $dots < 3 ) { // not completed CIDR
if ( $dots == 1 ) {
$net .= '.0.0';
} elseif ( $dots == 2 ) {
$net .= '.0';
}
}
if ( ! cerber_is_ipv4( $net ) ) {
return false;
}
if ( ! is_numeric( $mask ) ) {
return false;
}
$begin = long2ip( ( ip2long( $net ) ) & ( ( - 1 << ( 32 - (int) $mask ) ) ) );
$end = long2ip( ( ip2long( $net ) ) + pow( 2, ( 32 - (int) $mask ) ) - 1 );
return cerber_parse_ip( $begin . ' - ' . $end );
}
/**
* Try to recognize an IP range or a single IP in a string.
*
* @param $string string Network wildcard, CIDR or IP range.
*
* @return array|bool|string
*/
function cerber_any2range( $string = '' ) {
// Do not change the order!
$ret = cerber_wildcard2range( $string );
if ( ! $ret ) {
$ret = cerber_cidr2range( $string );
}
if ( ! $ret ) {
$ret = cerber_parse_ip( $string ); // must be last due to checking for cidr and wildcard
}
return $ret;
}
/*
Check for given IP address or subnet belong to this session.
*/
function cerber_is_myip( $ip ) {
global $wp_cerber;
if ( ! is_string( $ip ) ) {
return false;
}
$remote_ip = cerber_get_remote_ip();
if ( $ip == $remote_ip ) {
return true;
}
if ( $ip == cerber_get_subnet( $remote_ip ) ) {
return true;
}
return false;
}
function cerber_is_ip_in_range( $range, $ip = null ) {
global $wp_cerber;
if ( ! is_array( $range ) ) {
return false;
}
if ( ! $ip ) {
$ip = $wp_cerber->getRemoteIp();
}
$long = ip2long( $ip );
if ( $range['begin'] <= $long && $long <= $range['end'] ) {
return true;
}
return false;
}
/**
* Display 404 page to bump bots and bad guys
*
* @param bool $simple If true force displaying basic 404 page
*/
function cerber_404_page($simple = false) {
global $wp_query;
if ( !$simple ) {
if ( function_exists( 'status_header' ) ) {
status_header( '404' );
}
if ( isset( $wp_query ) && is_object( $wp_query ) ) {
$wp_query->set_404();
}
if ( 0 == crb_get_settings( 'page404' ) ) {
$template = null;
if ( function_exists( 'get_404_template' ) ) {
$template = get_404_template();
}
if ( function_exists( 'apply_filters' ) ) {
$template = apply_filters( 'cerber_404_template', $template );
}
if ( $template && @file_exists( $template ) ) {
include( $template );
exit;
}
}
}
header( 'HTTP/1.0 404 Not Found', true, 404 );
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>';
cerber_traffic_log(); // do not remove!
exit;
}
/*
Display Forbidden page
*/
function cerber_forbidden_page() {
status_header( '403' );
header( 'HTTP/1.0 403 Access Forbidden', true, 403 );
?>
<!DOCTYPE html>
<html style="height: 100%;">
<meta charset="UTF-8">
<head><title>403 Access Forbidden</title></head>
<body style="height: 100%;">
<div style="display: flex; align-items: center; justify-content: center; height: 70%;">
<div style="background-color: #eee; width: 70%; border: solid 3px #ddd; padding: 1.5em 3em 3em 3em; font-family: Arial, Helvetica, sans-serif;">
<div style="display: table-row;">
<div style="display: table-cell; font-size: 150px; color: red; vertical-align: middle; padding-right: 50px;">
✋
</div>
<div style="display: table-cell; vertical-align: middle;">
<h1><?php _e("We're sorry, you are not allowed to proceed", 'wp-cerber'); ?></h1>
<p>Our server stopped processing your request. Your request looks suspicious or similar to automated
requests from spam posting software.</p>
<p>If you believe you should be able to perform this request, please let us know.</p>
</div>
</div>
</div>
</div>
</body>
</html>
<?php
cerber_traffic_log(); // do not remove!
exit;
}
// Citadel mode -------------------------------------------------------------------------------------
function cerber_enable_citadel() {
global $wp_cerber;
if ( get_transient( 'cerber_citadel' ) ) {
return;
}
set_transient( 'cerber_citadel', true, crb_get_settings( 'ciduration' ) * 60 );
cerber_log( 12 );
// Notify admin
if ( $wp_cerber->getSettings( 'cinotify' ) ) {
cerber_send_email( 'citadel' );
}
}
function cerber_disable_citadel() {
delete_transient( 'cerber_citadel' );
}
function cerber_is_citadel() {
if ( get_transient( 'cerber_citadel' ) ) {
return true;
}
return false;
}
// Hardening -------------------------------------------------------------------------------------
//if (!cerber_acl_check(cerber_get_ip(),'W') && false) {
/*
if ($hardening['ping']) {
add_filter( 'xmlrpc_methods', 'remove_xmlrpc_pingback' );
function remove_xmlrpc_pingback( $methods ) {
unset($methods['pingback.ping']);
unset($methods['pingback.extensions.getPingbacks']);
return $methods;
}
add_filter( 'wp_headers', 'remove_pingback_header' );
function remove_pingback_header( $headers ) {
unset( $headers['X-Pingback'] );
return $headers;
}
}
*/
//pingback_ping();
/*
// Remove shortlink from HEAD <link rel='shortlink' href='http://адрес-сайта/?p=45' />
remove_action('wp_head', 'wp_shortlink_wp_head', 10, 0 );
*/
/**
*
* Send notification letter
*
* @param string $type Notification type
* @param string|array $msg Additional message
* @param string $ip Remote IP address, if applicable
*
* @return bool
*/
function cerber_send_email( $type = '', $msg = '', $ip = '' ) {
global $wp_cerber;
if ( ! $type ) {
return false;
}
/*
$super = false;
if ( function_exists( 'is_super_admin' ) ) {
$super = is_super_admin();
}
if ( $type == 'lockout' && !$usper()) {
*/
if ( $type == 'lockout' && ! is_admin() ) {
$rate = absint( crb_get_settings( 'emailrate' ) );
if ( $rate ) {
$last_em = cerber_get_set( '_cerber_last', 1, false );
$period = 60 * 60; // per hour
if ( $last_em ) {
if ( $last_em > ( time() - $period / $rate ) ) {
return false;
}
}
cerber_update_set( '_cerber_last', time(), 1, false, time() + $period );
}
}
$html_mode = false;
$subj = '[' . get_option( 'blogname' ) . '] ' . __( 'WP Cerber notify', 'wp-cerber' ) . ': ';
$body = '';
if ( is_array( $msg ) ) {
$msg = implode( "\n\n", $msg );
}
$last = null;
switch ( $type ) {
case 'citadel':
$max = cerber_db_get_var( 'SELECT MAX(stamp) FROM ' . CERBER_LOG_TABLE . ' WHERE activity = 7' );
if ( $max ) {
$last_date = cerber_date( $max );
//$last = $wpdb->get_row( 'SELECT * FROM ' . CERBER_LOG_TABLE . ' WHERE stamp = ' . $max . ' AND activity = 7' );
$last = cerber_db_get_row( 'SELECT * FROM ' . CERBER_LOG_TABLE . ' WHERE stamp = ' . $max . ' AND activity = 7', MYSQL_FETCH_OBJECT );
}
if ( ! $last ) { // workaround for the empty log table
$last = new stdClass();
$last->ip = CERBER_NO_REMOTE_IP;
$last->user_login = 'test';
}
$subj .= __( 'Citadel mode is activated', 'wp-cerber' );
$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";
$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";
$body .= __( 'View activity in dashboard', 'wp-cerber' ) . ': ' . cerber_admin_link( 'activity' ) . "\n\n";
//$body .= __('Change notification settings','wp-cerber').': '.cerber_admin_link();
break;
case 'lockout':
$max = cerber_db_get_var( 'SELECT MAX(stamp) FROM ' . CERBER_LOG_TABLE . ' WHERE activity IN (10,11)' );
if ( $max ) {
$last_date = cerber_date( $max );
$last = cerber_db_get_row( 'SELECT * FROM ' . CERBER_LOG_TABLE . ' WHERE stamp = ' . $max . ' AND activity IN (10,11)', MYSQL_FETCH_OBJECT );
}
if ( ! $last ) { // workaround for the empty log table
$last = new stdClass();
$last->ip = CERBER_NO_REMOTE_IP;
$last->user_login = 'test';
}
if ( ! $active = cerber_blocked_num() ) {
$active = 0;
}
if ( $last->ip && ( $block = cerber_get_block( $last->ip ) ) ) {
$reason = $block->reason;
}
else {
$reason = __( 'unspecified', 'wp-cerber' );
}
$subj .= __( 'Number of lockouts is increasing', 'wp-cerber' ) . ' (' . $active . ')';
$body = __( 'Number of active lockouts', 'wp-cerber' ) . ': ' . $active . "\n\n";
$body .= sprintf( __( 'Last lockout was added: %s for IP %s', 'wp-cerber' ), $last_date, $last->ip . ' (' . @gethostbyaddr( $last->ip ) . ')' ) . "\n\n";
$body .= __( 'Reason', 'wp-cerber' ) . ': ' . strip_tags($reason) . "\n\n";
$body .= __( 'View activity for this IP', 'wp-cerber' ) . ': ' . cerber_admin_link( 'activity' ) . '&filter_ip=' . $last->ip . "\n\n";
$body .= __( 'View lockouts in dashboard', 'wp-cerber' ) . ': ' . cerber_admin_link( 'lockouts' ) . "\n\n";
break;
case 'new_version':
$subj = __( 'A new version of WP Cerber is available to install', 'wp-cerber' );
$body = __( 'Hi!', 'wp-cerber' ) . "\n\n";
$body .= __( 'A new version of WP Cerber is available to install', 'wp-cerber' ) . "\n\n";
$body .= $msg . "\n\n";
$body .= __( 'Website', 'wp-cerber' ) . ': ' . crb_get_bloginfo( 'name' );
break;
case 'shutdown':
$subj = '[' . get_option( 'blogname' ) . '] ' . __( 'The WP Cerber security plugin has been deactivated', 'wp-cerber' );
$body .= __( 'The WP Cerber security plugin has been deactivated', 'wp-cerber' ) . "\n\n";
if ( ! is_user_logged_in() ) {
$u = __( 'Not logged in', 'wp-cerber' );
} else {
$user = wp_get_current_user();
$u = $user->display_name;
}
$body .= __( 'Website', 'wp-cerber' ) . ': ' . crb_get_bloginfo( 'name' ) . "\n";
$body .= __( 'By user', 'wp-cerber' ) . ': ' . $u . "\n";
$body .= __( 'From IP address', 'wp-cerber' ) . ': ' . cerber_get_remote_ip() . "\n";
$whois = cerber_ip_whois_info( cerber_get_remote_ip() );
if ( ! empty( $whois['data']['country'] ) ) {
$body .= __( 'From country', 'wp-cerber' ) . ': ' . cerber_country_name( $whois['data']['country'] );
}
break;
case 'activated':
$subj = '[' . get_option( 'blogname' ) . '] ' . __( 'The WP Cerber security plugin is now active', 'wp-cerber' );
$body .= __( 'WP Cerber is now active and has started protecting your site', 'wp-cerber' ) . "\n\n";
//$body .= __( 'Change notification settings', 'wp-cerber' ) . ': ' . cerber_admin_link('notifications') . "\n\n";
$body .= __( 'Getting Started Guide', 'wp-cerber' ) . "\n\n";
$body .= 'https://wpcerber.com/getting-started/' . "\n\n";
$body .= 'Be in touch with the developer. Subscribe to Cerber\'s newsletter: http://wpcerber.com/subscribe-newsletter/';
break;
case 'newlurl':
$subj .= __( 'New Custom login URL', 'wp-cerber' );
$body .= $msg;
break;
case 'subs':
$subj .= __( 'A new activity has been recorded', 'wp-cerber' );
$body = __( 'A new activity has been recorded', 'wp-cerber' ) . "\n\n";
$body .= $msg;
break;
case 'report':
$html_mode = true;
$subj = '[' . get_option( 'blogname' ) . '] WP Cerber Security: ' . __( 'Weekly report', 'wp-cerber' );
$body = cerber_generate_report();
$link = cerber_admin_link( 'notifications' );
$body .= '<br/>' . __( 'To change reporting settings visit', 'wp-cerber' ) . ' <a href="' . $link . '">' . $link . '</a>';
if ($msg) {
$body .= nl2br($msg);
}
break;
case 'scan':
$html_mode = true;
$subj = '[' . get_option( 'blogname' ) . '] WP Cerber Security: ' . __( 'Scanner Report', 'wp-cerber' );
$body = $msg;
$link = cerber_admin_link( 'scan_schedule' );
$body .= '<br/>' . __( 'To change reporting settings visit', 'wp-cerber' ) . ' <a href="' . $link . '">' . $link . '</a>';
break;
}
$to_list = cerber_get_email( $type, true );
$to = implode( ', ', $to_list );
$body_filtered = apply_filters( 'cerber_notify_body', $body, array( 'type' => $type,
'IP' => $ip,
'to' => $to,
'subject' => $subj
) );
if ( $body_filtered && is_string( $body_filtered ) ) {
$body = $body_filtered;
}
$footer = '';
if ( $lolink = cerber_get_login_url() ) {
$lourl = urldecode( $lolink );
if ( $html_mode ) {
$lourl = '<a href="' . $lolink . '">' . $lourl . '</a>';
}
$footer .= "\n\n" . __( 'Your login page:', 'wp-cerber' ) . ' ' . $lourl;
}
if ( $type == 'report' && $date = lab_lab(true) ) {
$footer .= "\n\n" . __( 'Your license is valid until', 'wp-cerber' ) . ' ' . $date;
}
$footer .= "\n\n\n" . __( 'This message was sent by', 'wp-cerber' ) . ' WP Cerber Security ' . CERBER_VER . "\n";
$footer .= 'https://wpcerber.com';
if ( $html_mode ) {
add_filter( 'wp_mail_content_type', 'cerber_enable_html' );
$footer = str_replace( "\n", '<br/>', $footer );
}
// Everything is prepared, let's send it out
$result = null;
if ( $to && $subj && $body ) {
if ( ! $html_mode ) {
cerber_pb_send( $subj, $body.$footer );
}
if ( $type == 'report') {
$result = true;
foreach ( $to_list as $email ) {
$lastus = '';
if ( $rec = cerber_get_last_login( null, $email ) ) {
$lastus = sprintf( __( 'Your last sign-in was %s from %s', 'wp-cerber' ), cerber_date( $rec->stamp ), $rec->ip . ' (' . cerber_country_name( $rec->country ) . ')' );
if ( $html_mode ) {
$lastus = '<br/><br/>' . $lastus;
}
else {
$lastus = "\n\n" . $lastus;
}
}
if ( ! wp_mail( $email, $subj, '<html>' . $body . $lastus . $footer . '</html>' ) ) {
$result = false;
}
}
}
else {
if ( function_exists( 'wp_mail' ) ) {
$body = $body . $footer;
if ( $html_mode ) {
$body = '<html>' . $body . '</html>';
}
$result = wp_mail( $to, $subj, $body );
}
}
}
remove_filter('wp_mail_content_type', 'cerber_enable_html');
$params = array( 'type' => $type, 'IP' => $ip, 'to' => $to, 'subject' => $subj );
if ( $result ) {
do_action( 'cerber_notify_sent', $body, $params );
}
else {
do_action( 'cerber_notify_fail', $body, $params );
}
return $result;
}
function cerber_enable_html() {
return 'text/html';
}
/**
* Generates a performance report
*
* @param int $period Days to look back
*
* @return string
*/
function cerber_generate_report($period = 7){
global $wpdb;
$period = absint( $period );
if ( ! $period ) {
$period = 7;
}
$ret = '';
$rows = array();
$stamp = time() - $period * 24 * 3600;
//$in = implode( ',', crb_get_activity_set( 'malicious' ) );
//$link_base = '<a href="' . cerber_activity_link( array( 2 ) ) . '">';
$base_url = cerber_admin_link( 'activity' );
$css_table = 'width: 95%; max-width: 1000px; margin:0 auto; margin-bottom: 10px; background-color: #f5f5f5; text-align: center; font-family: Arial, Helvetica, sans-serif;';
$css_td = 'padding: 0.5em 0.5em 0.5em 1em; text-align: left;';
$css_border = 'border-bottom: solid 2px #f9f9f9;';
$site_name = ( is_multisite() ) ? get_site_option( 'site_name' ) : get_option( 'blogname' );
$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>';
$kpi_list = cerber_calculate_kpi( $period );
foreach ($kpi_list as $kpi){
$rows[] = '<td style="'.$css_td.' text-align: right;">'.$kpi[1].'</td><td style="padding: 0.5em; text-align: left;">'.$kpi[0].'</td>';
}
$ret .= '<div style="text-align: center; '.$css_table.'"><table style="font-size: 130%; margin:0 auto;"><tr>' . implode( '</tr><tr>', $rows ) . '</tr></table></div>';
// Activities counters
$rows = array();
$rows[] = '<td style="'.$css_td.$css_border.'" colspan="2"><p style="line-height: 1.5em; font-weight: bold;">'.__('Activity details','wp-cerber').'</p></td>';
$activites = $wpdb->get_results( 'SELECT activity, COUNT(activity) cnt FROM ' . CERBER_LOG_TABLE . ' WHERE stamp > ' . $stamp . ' GROUP by activity ORDER BY cnt DESC' );
if ( $activites ) {
$lables = cerber_get_labels();
foreach ( $activites as $a ) {
$rows[] = '<td style="'.$css_border.$css_td.'">' . $lables[ $a->activity ] . '</td><td style="padding: 0.5em; text-align: center; width:10%;'.$css_border.'"><a href="'.$base_url.'&filter_activity='.$a->activity.'">' . $a->cnt . '</a></td>';
}
}
$ret .= '<table style="border-collapse: collapse; '.$css_table.'"><tr>' . implode( '</tr><tr>', $rows ) . '</tr></table>';
// Activities counters
$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' );
if ( $activites ) {
$rows = array();
$rows[] = '<td style="'.$css_td.$css_border.'" colspan="2"><p style="line-height: 1.5em; font-weight: bold;">'.__('Attempts to log in with non-existing usernames','wp-cerber').'</p></td>';
foreach ( $activites as $a ) {
$rows[] = '<td style="'.$css_border.$css_td.'">' . htmlspecialchars($a->user_login) . '</td><td style="padding: 0.5em; text-align: center; width:10%;'.$css_border.'"><a href="'.$base_url.'&filter_login='.$a->user_login.'">' . $a->cnt . '</a></td>';
}
$ret .= '<table style="border-collapse: collapse; '.$css_table.'"><tr>' . implode( '</tr><tr>', $rows ) . '</tr></table>';
}
$ret = '<div style="width:100%; padding: 1em; text-align: center; background-color: #f9f9f9;">' . $ret . '</div>';
return $ret;
}
// Maintenance routines ----------------------------------------------------------------
add_filter( 'cron_schedules', function ( $schedules ) {
$schedules['crb_five'] = array(
'interval' => 300,
'display' => 'Every 5 Minutes',
);
return $schedules;
} );
function cerber_init_cron(){
$next_hour = intval( floor( ( time() + 3600 ) / 3600 ) * 3600 );
if ( ! wp_next_scheduled( 'cerber_bg_launcher' ) ) {
wp_schedule_event( time(), 'crb_five', 'cerber_bg_launcher' );
}
if ( ! wp_next_scheduled( 'cerber_hourly_1' ) ) {
wp_schedule_event( $next_hour, 'hourly', 'cerber_hourly_1' );
}
if ( ! wp_next_scheduled( 'cerber_hourly_2' ) ) {
wp_schedule_event( $next_hour + 600 , 'hourly', 'cerber_hourly_2' );
}
if ( ! wp_next_scheduled( 'cerber_daily' ) ) {
wp_schedule_event( $next_hour + 1200, 'daily', 'cerber_daily' );
}
}
add_action( 'cerber_hourly_1', 'cerber_do_hourly' );
function cerber_do_hourly( $force = false ) {
global $wpdb, $wp_cerber;
$t = 'cerber_hourly_1';
$start = time();
// Avoid multiple executions on a weird hosting
if ( ( $last = get_site_transient( $t ) ) && date( 'G', $last[0] ) == date( 'G' ) ) {
return;
}
set_site_transient( $t, array( $start ), 2 * 3600 );
if ( is_multisite() ) {
if ( ! $force && get_site_transient( 'cerber_multisite' ) ) {
return;
}
set_site_transient( 'cerber_multisite', 'executed', 3600 );
}
$time = time();
$days = absint( crb_get_settings( 'keeplog' ) );
if ( $days > 0 ) {
$wpdb->query( 'DELETE FROM ' . CERBER_LOG_TABLE . ' WHERE stamp < ' . ( $time - $days * 24 * 3600 ) );
}
$days = absint( crb_get_settings( 'tikeeprec' ) );
if ( $days > 0 ) {
$wpdb->query( 'DELETE FROM ' . CERBER_TRAF_TABLE . ' WHERE stamp < ' . ( $time - $days * 24 * 3600 ) );
}
$wpdb->query( 'DELETE FROM ' . CERBER_LAB_IP_TABLE . ' WHERE expires < ' . $time );
if ( $wp_cerber->getSettings( 'trashafter-enabled') && absint($wp_cerber->getSettings('trashafter'))) {
$list = get_comments( array( 'status' => 'spam' ) );
if ( $list ) {
$time = time() - DAY_IN_SECONDS * absint($wp_cerber->getSettings( 'trashafter' ));
foreach ( $list as $item ) {
if ( $time > strtotime( $item->comment_date_gmt ) ) {
wp_trash_comment( $item->comment_ID );
}
}
}
}
cerber_up_data();
// Keep the size of the log file small
cerber_truncate_log();
set_site_transient( $t, array( $start, time() ), 2 * 3600 );
}
add_action( 'cerber_hourly_2', function () {
$t = 'cerber_hourly_2';
$start = time();
if ( ( $last = get_site_transient( $t ) ) && date( 'G', $last[0] ) == date( 'G' ) ) {
return;
}
set_site_transient( $t, array( $start ), 2 * 3600 );
$gmt_offset = get_option( 'gmt_offset' ) * 3600;
if ( crb_get_settings( 'enable-report' )
&& date( 'w', time() + $gmt_offset ) == crb_get_settings( 'wreports-day' )
&& date( 'G', time() + $gmt_offset ) == crb_get_settings( 'wreports-time' )
//&& ! get_site_transient( 'cerber_wreport' )
) {
$result = cerber_send_email( 'report' );
//set_site_transient( 'cerber_wreport', 'sent', 7200 );
update_site_option( '_cerber_report', array( time(), $result ) );
}
cerber_watchdog( true );
cerber_delete_expired_set();
// Cleanup the quarantine folder
if ( $dirs = glob( cerber_get_the_folder() . 'quarantine' . '/*', GLOB_ONLYDIR ) ) {
foreach ( $dirs as $dir ) {
$d = basename( $dir );
if ( is_numeric( $d ) ) {
if ( $d < ( time() - DAY_IN_SECONDS * crb_get_settings( 'scan_qcleanup' ) ) ) {
$fs = cerber_init_wp_filesystem();
if ( ! is_wp_error( $fs ) ) {
$fs->delete( $dir, true );
}
}
}
}
}
if ( crb_get_settings( 'cerberlab' ) || lab_lab() ) {
lab_check_nodes( true, true );
}
cerber_push_lab();
cerber_cloud_sync();
// Simply keep folder locked
cerber_get_the_folder();
cerber_db_query( 'DELETE FROM ' . CERBER_QMEM_TABLE . ' WHERE stamp < ' . ( time() - 30 * 60 ) );
set_site_transient( $t, array( $start, time() ), 2 * 3600 );
});
add_action( 'cerber_daily', 'cerber_do_daily' );
function cerber_do_daily() {
$t = 'cerber_daily_1';
$start = time();
if ( ( $last = get_site_transient( $t ) ) && date( 'j', $last[0] ) == date( 'j' ) ) {
return;
}
set_site_transient( $t, array( $start ), 48 * 3600 );
cerber_do_hourly( true );
$time = time();
lab_validate_lic();
cerber_db_query( 'DELETE FROM ' . CERBER_LAB_NET_TABLE . ' WHERE expires < ' . $time );
cerber_db_query( 'DELETE FROM ' . CERBER_LAB_TABLE . ' WHERE stamp < ' . ( $time - 3600 ) ); // workaround for weird/misconfigured hostings
cerber_db_query( 'OPTIMIZE TABLE ' . CERBER_LOG_TABLE );
cerber_db_query( 'OPTIMIZE TABLE ' . CERBER_QMEM_TABLE );
cerber_db_query( 'OPTIMIZE TABLE ' . CERBER_TRAF_TABLE );
cerber_db_query( 'OPTIMIZE TABLE ' . CERBER_ACL_TABLE );
cerber_db_query( 'OPTIMIZE TABLE ' . CERBER_BLOCKS_TABLE );
cerber_db_query( 'OPTIMIZE TABLE ' . CERBER_LAB_TABLE );
cerber_db_query( 'OPTIMIZE TABLE ' . CERBER_LAB_IP_TABLE );
cerber_db_query( 'OPTIMIZE TABLE ' . CERBER_LAB_NET_TABLE );
cerber_db_query( 'OPTIMIZE TABLE ' . cerber_get_db_prefix() . CERBER_SCAN_TABLE );
cerber_db_query( 'OPTIMIZE TABLE ' . cerber_get_db_prefix() . CERBER_SETS_TABLE );
cerber_db_query( 'OPTIMIZE TABLE ' . cerber_get_db_prefix() . CERBER_MS_LIST_TABLE );
if ( $new = cerber_check_for_newer() ) {
$history = get_site_option( '_cerber_notify_new' );
if ( ! $history || ! is_array( $history ) ) {
$history = array();
}
if ( ! in_array( $new['ver'], $history ) ) {
if ( crb_get_settings( 'notify-new-ver' ) ) {
cerber_send_email( 'new_version', 'Read more: https://wpcerber.com/?plugin_version=' . $new['ver'] );
}
$history[] = $new['ver'];
update_site_option( '_cerber_notify_new', $history );
}
}
if ( nexus_is_master() ) {
if ( ( $ups = get_site_transient( 'update_plugins' ) ) && $ups->response ) {
nexus_update_updates( obj_to_arr_deep( $ups->response ) );
}
}
// TODO: implement holding previous values for a while
// cerber_antibot_gene();
set_site_transient( $t, array( $start, time() ), 48 * 3600 );
}
add_action( 'cerber_bg_launcher', function () {
define( 'CRB_DOING_BG_TASK', 1 );
@set_time_limit( 180 );
@ini_set( 'max_execution_time', 180 );
if ( nexus_is_master() ) {
nexus_schedule_refresh();
}
cerber_bg_task_launcher();
} );
function cerber_bg_task_launcher( $filter = null ) {
$ret = array();
if ( ! $task_list = cerber_get_set( '_background_tasks' ) ) {
return $ret;
}
if ( $filter ) {
//$exec_it = array_intersect_key( $task_list, array_flip( crb_array_get( $_REQUEST, 'tasks', array() ) ) );
$exec_it = array_intersect_key( $task_list, $filter );
}
else {
$exec_it = $task_list;
}
if ( empty( $exec_it ) ) {
return $ret;
}
$safe_func = array( 'nexus_send', 'nexus_do_upgrade' );
foreach ( $exec_it as $task_id => $task ) {
$func = crb_array_get( $task, 'func' );
if ( ! is_callable( $func ) ) {
cerber_bg_task_delete( $task_id );
continue;
}
if ( ! in_array( $func, $safe_func ) ) {
cerber_diag_log( 'ERROR: Function ' . $func . ' is not in the safe list' );
cerber_bg_task_delete( $task_id );
continue;
}
if ( ! isset( $task['exec_until'] ) ) {
cerber_bg_task_delete( $task_id );
}
// Ready to lunch the task
$args = crb_array_get( $task, 'args', array() );
ob_start();
$result = call_user_func_array( $func, $args );
$echo = ob_get_clean();
if ( isset( $task['exec_until'] ) ) {
if ( $task['exec_until'] === $result ) {
cerber_bg_task_delete( $task_id );
}
}
if ( empty( $task['return'] ) ) {
$echo = ( $echo ) ? ' there was an output ' . strlen( $echo ) . ' bytes length' : 'no output';
$result = 1;
}
$ret[ $task_id ] = array( $result, crb_array_get( $task, 'run_js' ), $echo );
}
return $ret;
}
function cerber_bg_task_add( $task = array(), $priority = false, $limit = 60 ) {
$list = cerber_get_set( '_background_tasks' );
if ( ! $list ) {
$list = array();
}
$id = sha1( serialize( $task ) );
if ( isset( $list[ $id ] ) ) {
return false;
}
if ( $priority ) {
$list = array( $id => $task ) + $list;
}
else {
$list[ $id ] = $task;
}
return cerber_update_set( '_background_tasks', $list );
}
function cerber_bg_task_delete( $task_id ) {
if ( ! $list = cerber_get_set( '_background_tasks' ) ) {
return false;
}
if ( ! isset( $list[ $task_id ] ) ) {
return false;
}
unset( $list[ $task_id ] );
return cerber_update_set( '_background_tasks', $list );
}
/**
* Log activity
*
* @param int $activity Activity ID
* @param string $login Login used or any additional information
* @param int $user_id User ID
* @param null $ip IP Address
*
* @return false|int
* @since 3.0
*/
function cerber_log( $activity, $login = '', $user_id = 0, $ip = null ) {
global $user_ID, $cerber_logged, $cerber_blocked;
static $logged = array();
$wp_cerber = get_wp_cerber();
$activity = absint( $activity );
if ( isset( $logged[ $activity ] ) ) {
return false;
}
else {
$logged[ $activity ] = true;
}
$cerber_logged[ $activity ] = $activity;
//$wp_cerber->setProcessed();
if ( empty( $ip ) ) {
$ip = $wp_cerber->getRemoteIp();
}
elseif ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
return false;
}
if ( cerber_is_ipv4( $ip ) ) {
$ip_long = ip2long( $ip );
}
else {
$ip_long = 1;
}
if ( empty( $user_id ) ) {
$user_id = ( $user_ID ) ? $user_ID : 0;
}
$user_id = absint( $user_id );
$stamp = microtime( true );
$pos = strpos($_SERVER['REQUEST_URI'],'?');
if ($pos) {
$path = substr( $_SERVER['REQUEST_URI'], 0, $pos );
}
else {
$path = $_SERVER['REQUEST_URI'];
}
$url = strip_tags($_SERVER['HTTP_HOST'] . $path);
$status = 0;
if ( $activity != 10 && $activity != 11 ) {
$status = cerber_get_status( $ip );
}
elseif ( $cerber_blocked ) {
$status = $cerber_blocked;
}
$details = $status .'|0|0|0|'. $url;
$country = lab_get_country( $ip );
$login = cerber_real_escape( $login );
$details = cerber_real_escape( $details );
$ret = cerber_db_query( 'INSERT INTO ' . CERBER_LOG_TABLE . ' (ip, ip_long, user_login, user_id, stamp, activity, session_id, country, details)
VALUES ("' . $ip . '",' . $ip_long . ',"' . $login . '",' . $user_id . ',"' . $stamp . '",' . $activity . ',"' . $wp_cerber->getSessionID() . '","' . $country . '","' . $details . '")' );
if ( ! $ret ) {
cerber_watchdog();
}
// Subscriptions - notifications for admin ---------------------------------------------------
$subs = cerber_get_site_option( '_cerber_subs' );
if (!empty($subs)) {
foreach ( $subs as $hash => $sub ) {
// Loop through subscription parameters
if ( ! empty( $sub[0] )) {
if ( ! in_array( $activity, $sub[0] ) ) {
continue;
}
}
if ( ! empty( $sub[1] ) && $sub[1] != $user_id ) {
continue;
}
if ( ! empty( $sub[3] ) && ( $ip_long < $sub[2] || $sub[3] < $ip_long ) ) {
continue;
}
if ( ! empty( $sub[4] ) && $sub[4] != $ip ) {
continue;
}
if ( ! empty( $sub[5] ) && $sub[5] != $login ) {
continue;
}
if ( ! empty( $sub[6] ) ) {
$none = true;
if ( false !== strpos( $ip, $sub[6] ) ) {
$none = false;
}
elseif ( false !== mb_stripos( $login, $sub[6] ) ) {
$none = false;
}
elseif ( $user_id ) {
if ( ! $user = wp_get_current_user() ) {
$user = get_userdata( $user_id );
}
if ( false !== mb_stripos( $user->user_firstname, $sub[6] )
|| false !== mb_stripos( $user->user_lastname, $sub[6] )
|| false !== mb_stripos( $user->nickname, $sub[6] )) {
$none = false;
}
}
/*elseif ( $user_id && in_array( $user_id, $sub[8] ) ) {
$none = false;
}*/
if ( $none ) {
continue;
}
}
// Some parameter(s) matched, prepare and send notification
$labels = cerber_get_labels( 'activity' );
$msg = __( 'Activity', 'wp-cerber' ) . ': ' . $labels[$activity] . "\n\n";
if ( $country ) {
$coname = ' ('.cerber_country_name( $country ).')';
}
else {
$coname = '';
}
$msg .= __( 'IP', 'wp-cerber' ) . ': ' . $ip . $coname. "\n\n";
if ( $user_id && function_exists('get_userdata')) {
$u = get_userdata( $user_id );
$msg .= __( 'User', 'wp-cerber' ) . ': ' . $u->display_name . "\n\n";
}
if ( $login ) {
$msg .= __( 'Username used', 'wp-cerber' ) . ': ' . $login . "\n\n";
}
if ( ! empty( $sub['6'] ) ) {
$msg .= __( 'Search string', 'wp-cerber' ) . ': ' . $sub['6'] . "\n\n";
}
// Link to the Activity admin page
$args = cerber_subscribe_params();
$i = 0;
$link_params = '';
foreach ($args as $arg => $val){
if (is_array($sub[$i])){
foreach ( $sub[ $i ] as $item ) {
$link_params .= '&' . $arg . '[]=' . $item;
}
}
else {
$link_params .= '&' . $arg . '=' . $sub[ $i ];
}
$i++;
}
$link = cerber_admin_link( 'activity' ) . $link_params;
$msg .= __( 'View activity in dashboard', 'wp-cerber' ) . ': ' . $link;
$msg .= "\n\n" . __( 'To unsubscribe click here', 'wp-cerber' ) . ': ' . cerber_admin_link( 'activity' ) . '&unsubscribeme=' . $hash;
cerber_send_email( 'subs', $msg, $ip );
break; // Just one notification letter per event
}
}
if ( in_array( $activity, array( 16, 17, 40, 56, 100 ) ) ) {
lab_save_push( $ip, $activity, '' );
}
return $ret;
}
/**
* Get records from the log
*
* @param array $activity
* @param array $user
* @param array $order
* @param string $limit
*
* @return array|null
*/
function cerber_get_log($activity = array(), $user = array(), $order = array(), $limit = ''){
global $wpdb;
$where = array();
if ( $activity ) {
$activity = array_map( 'absint', $activity );
$where[] = 'activity IN (' . implode( ', ', $activity ) . ')';
}
if ( ! empty( $user['email'] ) ) {
$user = get_user_by( 'email', $user['email'] );
$where[] = 'user_id = ' . absint( $user->ID );
}
elseif ( ! empty( $user['id'] ) ) {
$where[] = 'user_id = ' . absint( $user['id'] );
}
$where_sql = '';
if ( $where ) {
$where_sql = ' WHERE ' . implode( ' AND ', $where );
}
$order_sql = '';
if ( $order ) {
if ( ! empty( $order['DESC'] ) ) {
$order_sql = ' ORDER BY ' . preg_replace( '/[^\w]/', '', $order['DESC'] ) . ' DESC ';
}
elseif ( ! empty( $order['ASC'] ) ) {
$order_sql = ' ORDER BY ' . preg_replace( '/[^\w]/', '', $order['ASC'] ) . ' ASC ';
}
}
$limit_sql = '';
if ( $limit ) {
$limit_sql = ' LIMIT ' . preg_replace( '/[^0-9\.]/', '', $limit );
}
// $row = $wpdb->get_row('SELECT * FROM '.CERBER_LOG_TABLE.' WHERE activity = 5 AND user_id = '.absint($user_id) . ' ORDER BY stamp DESC LIMIT 1');
return $wpdb->get_results( 'SELECT * FROM ' . CERBER_LOG_TABLE . ' ' . $where_sql . $order_sql . $limit_sql );
}
/**
* Return the last login record for a given user
*
* @param $user_id int|null
* @param $user_email string
*
* @return array|null|object|string
*/
function cerber_get_last_login( $user_id, $user_email = '' ) {
if ( $user_id ) {
$u = array( 'id' => $user_id );
}
elseif ( $user_email ) {
$u = array( 'email' => $user_email );
}
if ( ! $u ) {
return false;
}
if ( $recs = cerber_get_log( array( 5 ), $u, array( 'DESC' => 'stamp' ), 1 ) ) {
return $recs[0];
}
return false;
}
function cerber_count_log($activity = array(), $period = 1) {
$period = absint( $period );
if ( ! $period ) {
$period = 1;
}
$stamp = time() - $period * 24 * 3600;
// TODO: replace with SELECT COUNT(DISTINCT session_id)
$ret = cerber_db_get_var('SELECT COUNT(ip) FROM '. CERBER_LOG_TABLE .' WHERE activity IN ('.implode(',',$activity).') AND stamp > '. $stamp);
if (!$ret) $ret = 0;
return $ret;
}
/**
* Create a set of parameters for using it in Subscriptions
* The keys are used to built an URL. Values to calculate a hash.
*
* @return array The set of parameters
*/
function cerber_subscribe_params() {
// Mandatory parameters in a particular order.
$params = array( 'filter_activity' => 0, 'filter_user' => 0, 'begin' => 0, 'end' => 0, 'filter_ip' => 0, 'filter_login' => 0, 'search_activity' => 0, 'filter_role' => 0, 'user_ids' => 0 );
$begin = 0;
$end = 0;
$ip = 0;
$get = crb_get_query_params();
if ( ! empty( $get['filter_ip'] ) ) {
$ip = cerber_any2range( $get['filter_ip'] );
if ( is_array( $ip ) ) {
$begin = $ip['begin'];
$end = $ip['end'];
$ip = 0;
} elseif ( ! $ip ) {
$ip = 0;
}
}
$params['begin'] = $begin;
$params['end'] = $end;
$params['filter_ip'] = $ip;
$get_list = array( 'filter_activity', 'filter_user', 'filter_login', 'search_activity', 'filter_role', 'filter_set' );
foreach ( $get_list as $item ) {
if ( ! empty( $get[ $item ] ) ) {
if ( is_array( $get[ $item ] ) ) {
$params[ $item ] = array_map( 'trim', $get[ $item ] );
}
else {
$params[ $item ] = trim( $get[ $item ] );
}
}
else {
$params[ $item ] = 0;
}
//$params[ $item ] = ( empty( $_GET[ $item ] ) ) ? 0 : trim( $_GET[ $item ] );
}
if ( ! is_array( $params['filter_activity'] ) ) {
$params['filter_activity'] = array( $params['filter_activity'] );
}
$params['filter_activity'] = array_filter( $params['filter_activity'] );
// 'begin' and 'end' array keys are not used, added for compatibility
//return array( 'filter_activity' => $filter_activity, 'filter_user' => $filter_user, 'begin' => $begin, 'end' => $end, 'filter_ip' => $ip, 'filter_login' => $filter_login, 'search_activity' => $search_activity, 'filter_role' => $filter_role );
return $params;
}
/**
* Loads must have settings
* @since 7.8.3
*
*/
function cerber_pre_checks() {
// Load must have settings before the rest of the stuff during the plugin activation
// The only way to get it done earlier
if ( cerber_get_get( 'action' ) === 'activate'
&& cerber_get_get( 'plugin' ) === CERBER_PLUGIN_ID ) {
// The plugin is activated in wp-admin
if ( ! crb_get_settings() ) {
define('CRB_JUST_MARRIED', 1);
cerber_load_defaults();
}
}
// A backup way
add_action( 'activated_plugin', function ( $plugin ) {
if ( $plugin !== CERBER_PLUGIN_ID ) {
return;
}
if ( ! crb_get_settings() ) {
if ( ! defined( 'CRB_JUST_MARRIED' ) ) {
define( 'CRB_JUST_MARRIED', 1 );
}
cerber_load_defaults();
}
} );
}
/**
* Post plugin activation stuff
*
*/
register_activation_hook( cerber_plugin_file(), function () {
$assets_url = cerber_plugin_dir_url() . 'assets';
load_plugin_textdomain( 'wp-cerber', false, basename( dirname( __FILE__ ) ) . '/languages' );
if ( version_compare( CERBER_REQ_PHP, phpversion(), '>' ) ) {
cerber_stop_activating( '<h3>' . sprintf( __( 'The WP Cerber requires PHP %s or higher. You are running', 'wp-cerber' ), CERBER_REQ_PHP ) . ' ' . phpversion() . '</h3>' );
}
if ( version_compare( CERBER_REQ_WP, cerber_get_wp_version(), '>' ) ) {
cerber_stop_activating( '<h3>' . sprintf( __( 'The WP Cerber requires WordPress %s or higher. You are running', 'wp-cerber' ), CERBER_REQ_WP ) . ' ' . cerber_get_wp_version() . '</h3>' );
}
$db_errors = cerber_create_db();
if ( $db_errors ) {
$e = '';
foreach ( $db_errors as $db_error ) {
$e .= '<p>' . implode( '</p><p>', $db_error ) . '</p>';
}
cerber_stop_activating( '<h3>' . __( "Can't activate WP Cerber due to a database error.", 'wp-cerber' ) . '</h3>'.$e);
}
lab_get_key( true );
cerber_upgrade_all( true );
cerber_cookie_one();
cerber_disable_citadel();
$wp_cerber = get_wp_cerber();
cerber_add_white( cerber_get_subnet( $wp_cerber->getRemoteIp() ) , 'My subnet' ); // Protection for non-experienced user
cerber_htaccess_sync( 'main' );
cerber_htaccess_sync( 'media' );
cerber_set_boot_mode();
cerber_admin_message(
'<img style="float:left; margin-left:-10px;" src="' . $assets_url . '/icon-128x128.png">' .
'<p style="font-size:120%;">' . __( 'WP Cerber is now active and has started protecting your site', 'wp-cerber' ) . '</p>' .
' <p>' . __( 'Your IP address is added to the', 'wp-cerber' ) . ' ' . __( 'White IP Access List', 'wp-cerber' ) .
' <p style="font-size:130%;"><a href="http://wpcerber.com/getting-started/" target="_blank">' . __( 'Getting Started Guide', 'wp-cerber' ) . '</a></p>' .
//' <p><b>' . __( "It's important to check security settings.", 'wp-cerber' ) . '</b> <a href="http://wpcerber.com/" target="_blank">Read Cerber\'s blog</a> ' .
//' <a href="http://wpcerber.com/subscribe-newsletter/" target="_blank">Subscribe to Cerber\'s newsletter</a></p>' .
' <p>
</p>
<p id="crb-activation-msg">
<i class="crb-icon crb-icon-bx-slider"></i> <a href="' . cerber_admin_link( 'main' ) . '">' . __( 'Main Settings', 'wp-cerber' ) . '</a>' .
' <i class="crb-icon crb-icon-bx-radar"></i> <a href="' . cerber_admin_link( 'scan_main' ) . '">' . __( 'Security Scanner', 'wp-cerber' ) . '</a>' .
' <i class="crb-icon crb-icon-bx-lock"></i> <a href="' . cerber_admin_link( 'acl' ) . '">' . __( 'Access Lists', 'wp-cerber' ) . '</a>' .
' <i class="crb-icon crb-icon-bxs-shield"></i> <a href="' . cerber_admin_link( 'antispam' ) . '">' . __( 'Antispam', 'wp-cerber' ) . '</a>' .
' <i class="crb-icon crb-icon-bx-shield-alt"></i> <a href="' . cerber_admin_link( 'hardening' ) . '">' . __( 'Hardening', 'wp-cerber' ) . '</a>' .
' <i class="crb-icon crb-icon-bx-bell"></i> <a href="' . cerber_admin_link( 'notifications' ) . '">' . __( 'Notifications', 'wp-cerber' ) . '</a>' .
' <i class="crb-icon crb-icon-bx-layer"></i> <a href="' . cerber_admin_link( 'imex' ) . '">' . __( 'Import settings', 'wp-cerber' ) . '</a>' .
'</p>' );
if ( ! defined( 'CRB_JUST_MARRIED' ) || ! CRB_JUST_MARRIED ) {
return;
}
cerber_send_email( 'activated' );
$p = get_file_data( cerber_plugin_file(), array( 'Version' => 'Version' ), 'plugin' );
$p['time'] = time();
$p['user'] = get_current_user_id();
cerber_update_set( '_activated', $p );
});
/*
Abort activating plugin!
*/
function cerber_stop_activating( $msg ) {
//deactivate_plugins( cerber_plug_in() );
deactivate_plugins( CERBER_PLUGIN_ID );
wp_die( $msg );
}
// Closure can't be used
register_uninstall_hook( cerber_plugin_file(), 'cerber_finito' );
function cerber_finito() {
if ( ! is_super_admin() ) {
return;
}
$dir = cerber_get_the_folder();
if ( ! is_wp_error( $dir ) && file_exists( $dir ) ) {
$fs = cerber_init_wp_filesystem();
if ( ! is_wp_error( $fs ) ) {
$fs->rmdir( $dir, true );
}
}
$list = array( '_cerber_up', '_cerber_report', 'cerber-groove', 'cerber-groove-x', '_cerberkey_', 'cerber-antibot', 'cerber_admin_info', '_cerber_db_errors' );
$list = array_merge( $list, cerber_get_setting_list() );
foreach ( $list as $opt ) {
delete_site_option( $opt );
}
// Must be executed last
cerber_db_query( 'DROP TABLE IF EXISTS ' . implode( ',', cerber_get_tables() ) );
}
/**
* Upgrade database tables, data and plugin settings
*
* @since 3.0
*
*/
function cerber_upgrade_all( $force = false ) {
global $cerber_doing_upgrade;
$ver = get_site_option( '_cerber_up' );
if ( $force || ! $ver || $ver['v'] != CERBER_VER ) {
$d = @ini_get( 'display_errors');
@ini_set( 'display_errors', 0 );
$cerber_doing_upgrade = true;
@define( 'CRB_DOING_UPGRADE', 1 );
crb_clear_admin_msg();
cerber_create_db();
cerber_upgrade_db();
cerber_acl_fixer( true );
cerber_antibot_gene( true );
cerber_upgrade_settings();
cerber_htaccess_sync( 'main' );
wp_clear_scheduled_hook( 'cerber_hourly' ); // @since 5.8
update_site_option( '_cerber_up', array( 'v' => CERBER_VER, 't' => time() ) );
cerber_push_the_news( CERBER_VER );
cerber_delete_expired_set( true );
lab_get_key( true );
$cerber_doing_upgrade = false;
delete_site_transient( 'update_plugins' );
@ini_set( 'display_errors', $d );
}
}
/**
* Creates DB tables if they don't exist
*
* @param bool $recreate If true, recreate some tables completely (with data lost)
*
* @return array Errors
*/
function cerber_create_db($recreate = true) {
global $wpdb;
$wpdb->hide_errors();
$db_errors = array();
$sql = array();
if ( ! cerber_is_table( CERBER_LOG_TABLE ) ) {
$sql[] = "
CREATE TABLE IF NOT EXISTS " . CERBER_LOG_TABLE . " (
ip varchar(39) CHARACTER SET ascii NOT NULL COMMENT 'Remote IP',
user_login varchar(60) NOT NULL COMMENT 'Username from HTTP request',
user_id bigint(20) unsigned NOT NULL DEFAULT '0',
stamp bigint(20) unsigned NOT NULL COMMENT 'Unix timestamp',
activity int(10) unsigned NOT NULL DEFAULT '0',
KEY ip (ip)
) DEFAULT CHARSET=utf8 COMMENT='Cerber activity log';
";
}
if ( ! cerber_is_table( CERBER_ACL_TABLE ) ) {
$sql[] = "
CREATE TABLE IF NOT EXISTS " . CERBER_ACL_TABLE . " (
ip varchar(39) CHARACTER SET ascii NOT NULL COMMENT 'IP',
tag char(1) NOT NULL COMMENT 'Type: B or W',
comments varchar(250) NOT NULL,
UNIQUE KEY ip (ip)
) DEFAULT CHARSET=utf8 COMMENT='Cerber IP Access Lists';
";
}
if ( ! cerber_is_table( CERBER_BLOCKS_TABLE ) ) {
$sql[] = "
CREATE TABLE IF NOT EXISTS " . CERBER_BLOCKS_TABLE . " (
ip varchar(39) CHARACTER SET ascii NOT NULL COMMENT 'Remote IP',
block_until bigint(20) unsigned NOT NULL COMMENT 'Unix timestamp',
reason varchar(250) NOT NULL COMMENT 'Why IP was blocked',
reason_id int(11) unsigned NOT NULL DEFAULT '0',
UNIQUE KEY ip (ip)
) DEFAULT CHARSET=utf8 COMMENT='Cerber list of currently blocked IPs';
";
}
if ( ! cerber_is_table( CERBER_LAB_TABLE ) ) {
$sql[] = "
CREATE TABLE IF NOT EXISTS " . CERBER_LAB_TABLE . " (
ip varchar(39) CHARACTER SET ascii NOT NULL COMMENT 'Remote IP',
reason_id int(11) unsigned NOT NULL DEFAULT '0',
stamp bigint(20) unsigned NOT NULL COMMENT 'Unix timestamp',
details text NOT NULL
) DEFAULT CHARSET=utf8 COMMENT='Cerber lab cache';
";
}
if ( $recreate || ! cerber_is_table( CERBER_LAB_IP_TABLE ) ) {
if ( $recreate && cerber_is_table( CERBER_LAB_IP_TABLE ) ) {
$sql[] = 'DROP TABLE IF EXISTS ' . CERBER_LAB_IP_TABLE;
}
$sql[] = "
CREATE TABLE IF NOT EXISTS " . CERBER_LAB_IP_TABLE . " (
ip varchar(39) CHARACTER SET ascii NOT NULL COMMENT 'IP',
reputation INT(11) UNSIGNED NOT NULL COMMENT 'Reputation of IP',
expires INT(11) UNSIGNED NOT NULL COMMENT 'Unix timestamp',
PRIMARY KEY (ip)
) DEFAULT CHARSET=utf8 COMMENT='Cerber lab IP cache';
";
}
if ( $recreate || ! cerber_is_table( CERBER_LAB_NET_TABLE ) ) {
if ( $recreate && cerber_is_table( CERBER_LAB_NET_TABLE ) ) {
$sql[] = 'DROP TABLE IF EXISTS ' . CERBER_LAB_NET_TABLE;
}
$sql[] = '
CREATE TABLE IF NOT EXISTS ' . CERBER_LAB_NET_TABLE . ' (
ip varchar(39) CHARACTER SET ascii NOT NULL DEFAULT "" COMMENT "IP address",
ip_long_begin BIGINT UNSIGNED NOT NULL DEFAULT "0",
ip_long_end BIGINT UNSIGNED NOT NULL DEFAULT "0",
country CHAR(3) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL DEFAULT "" COMMENT "Country code",
expires INT(11) UNSIGNED NOT NULL DEFAULT "0",
PRIMARY KEY (ip),
UNIQUE KEY begin_end (ip_long_begin, ip_long_end)
) DEFAULT CHARSET=utf8 COMMENT="Cerber lab network cache";
';
}
if ( ! cerber_is_table( CERBER_GEO_TABLE ) ) {
$sql[] = '
CREATE TABLE IF NOT EXISTS ' . CERBER_GEO_TABLE . ' (
country CHAR(3) NOT NULL DEFAULT "" COMMENT "Country code",
locale CHAR(10) NOT NULL DEFAULT "" COMMENT "Locale i18n",
country_name VARCHAR(250) NOT NULL DEFAULT "" COMMENT "Country name",
PRIMARY KEY (country, locale)
) DEFAULT CHARSET=utf8;
';
}
if ( ! cerber_is_table( CERBER_TRAF_TABLE ) ) {
$sql[] = '
CREATE TABLE IF NOT EXISTS ' . CERBER_TRAF_TABLE . ' (
ip varchar(39) CHARACTER SET ascii NOT NULL,
ip_long BIGINT UNSIGNED NOT NULL DEFAULT "0",
hostname varchar(250) NOT NULL DEFAULT "",
uri text NOT NULL,
request_fields MEDIUMTEXT NOT NULL,
request_details MEDIUMTEXT NOT NULL,
session_id char(32) CHARACTER SET ascii NOT NULL,
user_id bigint(20) UNSIGNED NOT NULL DEFAULT 0,
stamp decimal(14,4) NOT NULL,
processing int(10) NOT NULL DEFAULT 0,
country char(3) CHARACTER SET ascii NOT NULL DEFAULT "",
request_method char(8) CHARACTER SET ascii NOT NULL,
http_code int(10) UNSIGNED NOT NULL,
wp_id bigint(20) UNSIGNED NOT NULL DEFAULT 0,
wp_type int(10) UNSIGNED NOT NULL DEFAULT 0,
is_bot int(10) UNSIGNED NOT NULL DEFAULT 0,
blog_id int(10) UNSIGNED NOT NULL DEFAULT 0,
KEY stamp (stamp)
) DEFAULT CHARSET=utf8;
';
}
if ( ! cerber_is_table( cerber_get_db_prefix() . CERBER_SCAN_TABLE ) ) {
$sql[] = '
CREATE TABLE IF NOT EXISTS ' . cerber_get_db_prefix(). CERBER_SCAN_TABLE . ' (
scan_id INT(10) UNSIGNED NOT NULL,
scan_type INT(10) UNSIGNED NOT NULL DEFAULT 1,
scan_mode INT(10) UNSIGNED NOT NULL DEFAULT 0,
scan_status INT(10) UNSIGNED NOT NULL DEFAULT 0,
file_name_hash VARCHAR(255) CHARACTER SET ascii NOT NULL DEFAULT "",
file_name TEXT NOT NULL,
file_type INT(10) UNSIGNED NOT NULL DEFAULT 0,
file_hash VARCHAR(255) CHARACTER SET ascii NOT NULL DEFAULT "",
file_md5 VARCHAR(255) CHARACTER SET ascii NOT NULL DEFAULT "",
file_hash_repo VARCHAR(255) CHARACTER SET ascii NOT NULL DEFAULT "",
hash_match INT(10) UNSIGNED NOT NULL DEFAULT 0,
file_size BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
file_perms INT(11) NOT NULL DEFAULT 0,
file_writable INT(10) UNSIGNED NOT NULL DEFAULT 0,
file_mtime INT(10) UNSIGNED NOT NULL DEFAULT 0,
extra TEXT NOT NULL,
PRIMARY KEY (scan_id, file_name_hash)
) DEFAULT CHARSET=utf8;
';
}
if ( ! cerber_is_table( cerber_get_db_prefix() . CERBER_SETS_TABLE ) ) {
$sql[] = '
CREATE TABLE IF NOT EXISTS ' . cerber_get_db_prefix() . CERBER_SETS_TABLE . ' (
the_key VARCHAR(255) CHARACTER SET ascii NOT NULL,
the_id BIGINT(20) NOT NULL DEFAULT 0,
the_value LONGTEXT NOT NULL,
expires BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY (the_key, the_id)
) DEFAULT CHARSET=utf8;
';
}
if ( ! cerber_is_table( CERBER_QMEM_TABLE ) ) {
$sql[] = '
CREATE TABLE IF NOT EXISTS ' . CERBER_QMEM_TABLE . ' (
ip varchar(39) CHARACTER SET ascii NOT NULL,
http_code int(10) UNSIGNED NOT NULL,
stamp int(10) UNSIGNED NOT NULL,
KEY ip_stamp (ip, stamp)
) DEFAULT CHARSET=utf8;
';
}
foreach ( $sql as $query ) {
if ( ! $wpdb->query( $query ) && $wpdb->last_error ) {
$db_errors[] = array( $wpdb->last_error, $wpdb->last_query );
}
}
return $db_errors;
}
/**
* Upgrade structure of existing DB tables
*
* @return array Errors during upgrading
* @since 3.0
*/
function cerber_upgrade_db( $force = false ) {
global $wpdb;
$wpdb->hide_errors();
if ( $force ) {
$wpdb->suppress_errors();
}
$db_errors = array();
$sql = array();
// @since 3.0
$sql[] = 'ALTER TABLE ' . CERBER_LOG_TABLE . ' CHANGE stamp stamp DECIMAL(14,4) NOT NULL';
// @since 3.1
if ( $force || ! cerber_is_column( CERBER_LOG_TABLE, 'ip_long' ) ) {
$sql[] = 'ALTER TABLE ' . CERBER_LOG_TABLE . ' ADD ip_long BIGINT UNSIGNED NOT NULL DEFAULT "0" COMMENT "IPv4 long" AFTER ip, ADD INDEX (ip_long)';
}
if ( $force || ! cerber_is_column( CERBER_ACL_TABLE, 'ip_long_begin' ) ) {
$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";
}
if ( $force || !cerber_is_index( CERBER_ACL_TABLE, 'ip_begin_end' ) ) {
$sql[] = 'ALTER TABLE ' . CERBER_ACL_TABLE . ' ADD UNIQUE ip_begin_end (ip, ip_long_begin, ip_long_end)';
}
if ( $force || cerber_is_index( CERBER_ACL_TABLE, 'ip' ) ) {
$sql[] = 'ALTER TABLE ' . CERBER_ACL_TABLE . ' DROP INDEX ip';
}
// @since 4.8.2
if ( $force || cerber_is_index( CERBER_ACL_TABLE, 'begin_end' ) ) {
$sql[] = 'ALTER TABLE ' . CERBER_ACL_TABLE . ' DROP INDEX begin_end';
}
if ( $force || !cerber_is_index( CERBER_ACL_TABLE, 'begin_end_tag' ) ) {
$sql[] = 'ALTER TABLE ' . CERBER_ACL_TABLE . ' ADD INDEX begin_end_tag (ip_long_begin, ip_long_end, tag)';
}
// @since 4.9
if ( $force || ! cerber_is_column( CERBER_LOG_TABLE, 'session_id' ) ) {
$sql[] = 'ALTER TABLE ' . CERBER_LOG_TABLE . '
ADD session_id CHAR(32) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL DEFAULT "",
ADD country CHAR(3) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL DEFAULT "" COMMENT "Country code",
ADD details VARCHAR(250) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL DEFAULT "" COMMENT "Details about HTTP request";
';
}
// @since 6.1
if ( $force || ! cerber_is_index( CERBER_LOG_TABLE, 'session_index' ) ) {
$sql[] = 'ALTER TABLE ' . CERBER_LOG_TABLE . ' ADD INDEX session_index (session_id)';
}
// @since 7.0.3
$sql[] = 'DROP TABLE IF EXISTS ' . CERBER_SCAN_TABLE;
// @since 7.1
if ( $force || ! cerber_is_column( cerber_get_db_prefix() . CERBER_SCAN_TABLE, 'file_status' ) ) {
$sql[] = 'ALTER TABLE ' . cerber_get_db_prefix() . CERBER_SCAN_TABLE . " ADD file_status INT UNSIGNED NOT NULL DEFAULT '0' AFTER scan_status";
}
// @since 7.5.2
if ( $force || ! cerber_is_column( CERBER_BLOCKS_TABLE, 'reason_id' ) ) {
$sql[] = 'ALTER TABLE ' . CERBER_BLOCKS_TABLE . ' ADD reason_id int(11) unsigned NOT NULL DEFAULT "0"';
}
// @since 7.8.6
if ( $force || ! cerber_is_column( CERBER_TRAF_TABLE, 'php_errors' ) ) {
$sql[] = 'ALTER TABLE ' . CERBER_TRAF_TABLE . ' ADD php_errors TEXT NOT NULL AFTER blog_id';
}
if (!empty($sql)) {
foreach ( $sql as $query ) {
if ( !$wpdb->query( $query ) && $wpdb->last_error ) {
$db_errors[] = array( $wpdb->last_error, $wpdb->last_query );
}
}
}
cerber_acl_fixer();
update_site_option( '_cerber_db_errors', $db_errors );
return $db_errors;
}
function cerber_get_tables() {
return array(
CERBER_LOG_TABLE,
CERBER_QMEM_TABLE,
CERBER_TRAF_TABLE,
CERBER_ACL_TABLE,
CERBER_BLOCKS_TABLE,
CERBER_LAB_TABLE,
CERBER_LAB_IP_TABLE,
CERBER_LAB_NET_TABLE,
CERBER_GEO_TABLE,
cerber_get_db_prefix() . CERBER_SCAN_TABLE,
cerber_get_db_prefix() . CERBER_SETS_TABLE,
cerber_get_db_prefix() . CERBER_MS_TABLE,
cerber_get_db_prefix() . CERBER_MS_LIST_TABLE,
);
}
/**
* Updating old activity log records to the new row format (has been introduced in v 3.1)
*
* @since 4.0
*
*/
function cerber_up_data() {
$ips = cerber_db_get_col( 'SELECT DISTINCT ip FROM ' . CERBER_LOG_TABLE . ' WHERE ip_long = 0 LIMIT 50' );
if ( ! $ips ) {
return;
}
foreach ( $ips as $ip ) {
if ( cerber_is_ipv4( $ip ) ) {
$ip_long = ip2long( $ip );
} else {
$ip_long = 1;
}
cerber_db_query( 'UPDATE ' . CERBER_LOG_TABLE . ' SET ip_long = ' . $ip_long . ' WHERE ip = "' . $ip .'" AND ip_long = 0');
}
}
/**
* Upgrade corrupted / outdated rows in ACL
*
* @param bool $ipv6 if true Process IPv6 addresses
*
*/
function cerber_acl_fixer( $ipv6 = false ) {
global $wpdb;
// Repair/update IPs without long values
$ips = cerber_db_get_col( 'SELECT ip FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin = 0 OR ip_long_end = 0' );
if ( ! $ips ) {
return;
}
foreach ( $ips as $ip ) {
if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) ) {
continue;
}
$range = cerber_any2range( $ip );
if ( is_array( $range ) ) {
$begin = $range['begin'];
$end = $range['end'];
}
else {
$begin = ip2long( $ip );
$end = ip2long( $ip );
}
cerber_db_query( 'UPDATE ' . CERBER_ACL_TABLE . ' SET ip_long_begin = ' . $begin . ', ip_long_end = ' . $end . ' WHERE ip = "' . $ip . '"' );
}
// Convert old IPv6 to all shortened
if ( $ipv6 ) {
$ips = cerber_db_get_col( 'SELECT ip FROM ' . CERBER_ACL_TABLE . ' WHERE ip_long_begin = 0' );
if ( $ips ) {
foreach ( $ips as $ip ) {
if ( ! filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) ) {
continue;
}
$short_ip = cerber_short_ipv6( $ip );
if ( $short_ip != $ip ) {
cerber_db_query( 'UPDATE ' . CERBER_ACL_TABLE . ' SET ip = "' . $short_ip . '" WHERE ip = "' . $ip . '"' );
}
}
}
}
}
add_action( 'deac' . 'tivate_' . CERBER_PLUGIN_ID, function ( $ip ) {
wp_clear_scheduled_hook( 'cerber_bg_launcher' );
wp_clear_scheduled_hook( 'cerber_hourly_1' );
wp_clear_scheduled_hook( 'cerber_hourly_2' );
wp_clear_scheduled_hook( 'cerber_daily' );
cerber_htaccess_clean_up();
cerber_set_boot_mode( 0 );
cerber_delete_expired_set( true );
cerber_delete_set( 'plugins_done' );
cerber_delete_set( '_background_tasks' );
$pi = get_file_data( cerber_plugin_file(), array( 'Version' => 'Version' ), 'plugin' );
$pi ['v'] = time();
$pi ['u'] = get_current_user_id();
cerber_update_set( '_cerber_o' . 'ff', $pi );
$f = 'cerb' . 'er_se' . 'nd_em' . 'ail';
$f( 'sh' . 'utd' . 'own' );
} );
/*
Fix an issue with the empty user_id field in the comments table.
*/
add_filter( 'preprocess_comment', 'cerber_add_uid' );
function cerber_add_uid( $commentdata ) {
$current_user = wp_get_current_user();
$commentdata['user_ID'] = $current_user->ID;
return $commentdata;
}
/**
* Load jQuery on the page
*
*/
add_action( 'login_enqueue_scripts', 'cerber_login_scripts' );
function cerber_login_scripts() {
if ( cerber_antibot_enabled( array('botsreg', 'botsany') ) ) {
wp_enqueue_script( 'jquery' );
}
}
add_action( 'wp_enqueue_scripts', 'cerber_scripts' );
function cerber_scripts() {
global $wp_cerber;
if ( ( is_singular() && cerber_antibot_enabled( array( 'botscomm', 'botsany' ) ) )
|| ( $wp_cerber->getSettings( 'sitekey' ) && $wp_cerber->getSettings( 'secretkey' ) )
) {
wp_enqueue_script( 'jquery' );
}
}
/**
* Footer stuff like JS code
* Explicit rendering reCAPTCHA
*
*/
add_action( 'login_footer', 'cerber_login_register_stuff', 1000 );
function cerber_login_register_stuff() {
global $wp_cerber;
cerber_antibot_code(array( 'botsreg', 'botsany' ));
// Universal JS
if (!$wp_cerber->recaptcha_here) return;
$sitekey = $wp_cerber->getSettings('sitekey');
if (!$wp_cerber->getSettings('invirecap')){
// Classic version (visible reCAPTCHA)
echo '<script src = https://www.google.com/recaptcha/api.js?hl='.cerber_recaptcha_lang().' async defer></script>';
}
else {
// Pure JS version with explicit rendering
?>
<script src="https://www.google.com/recaptcha/api.js?onload=init_recaptcha_widgets&render=explicit&hl=<?php echo cerber_recaptcha_lang(); ?>" async defer></script>
<script type='text/javascript'>
document.getElementById("cerber-recaptcha").remove();
var init_recaptcha_widgets = function () {
for (var i = 0; i < document.forms.length; ++i) {
var form = document.forms[i];
var place = form.querySelector('.cerber-form-marker');
if (null !== place) render_recaptcha_widget(form, place);
}
};
function render_recaptcha_widget(form, place) {
var place_id = grecaptcha.render(place, {
'callback': function (g_recaptcha_response) {
HTMLFormElement.prototype.submit.call(form);
},
'sitekey': '<?php echo $sitekey; ?>',
'size': 'invisible',
'badge': 'bottomright'
});
form.onsubmit = function (event) {
event.preventDefault();
grecaptcha.execute(place_id);
};
}
</script>
<?php
}
}
/**
* Inline reCAPTCHA widget
*
*/
add_action( 'wp_footer', 'cerber_foo', 1000 );
function cerber_foo() {
global $wp_cerber;
if (is_singular()) cerber_antibot_code( array( 'botscomm', 'botsany' ) );
if (!$wp_cerber->recaptcha_here) return;
// jQuery version with support visible and invisible reCAPTCHA
// TODO: convert it into pure JS
?>
<script type="text/javascript">
jQuery(document).ready(function ($) {
var recaptcha_ok = false;
var the_recaptcha_widget = $("#cerber-recaptcha");
var is_recaptcha_visible = ($(the_recaptcha_widget).data('size') !== 'invisible');
var the_form = $(the_recaptcha_widget).closest("form");
var the_button = $(the_form).find('input[type="submit"]');
if (!the_button.length) {
the_button = $(the_form).find(':button');
}
// visible
if (the_button.length && is_recaptcha_visible) {
the_button.prop("disabled", true);
the_button.css("opacity", 0.5);
}
window.form_button_enabler = function () {
if (!the_button.length) return;
the_button.prop("disabled", false);
the_button.css( "opacity", 1 );
};
// invisible
if (!is_recaptcha_visible) {
$(the_button).click(function (event) {
if (recaptcha_ok) return;
event.preventDefault();
grecaptcha.execute();
});
}
window.now_submit_the_form = function () {
recaptcha_ok = true;
$(the_button).click(); // this is only way to submit a form that contains "submit" inputs
};
});
</script>
<script src = "https://www.google.com/recaptcha/api.js?hl=<?php echo cerber_recaptcha_lang(); ?>" async defer></script>
<?php
}
register_shutdown_function( function () {
cerber_extra_vision();
// Error monitoring
if ( 400 <= http_response_code()
&& ! cerber_is_wp_cron()
&& ! ( cerber_is_wp_ajax() && ( 400 == http_response_code() ) )
&& ( $mode = crb_get_settings( 'tierrmon' ) ) ) {
cerber_error_shield( $mode );
}
cerber_push_lab();
cerber_traffic_log();
} );
function cerber_error_shield( $mode = 1 ) {
global $cerber_status, $cerber_blocked;
if ( ! $mode || ( crb_get_settings( 'tierrnoauth' ) && is_user_logged_in() ) ) {
return;
}
$time = 900;
$limit = 3; // allowed within $time
$codes = array();
if ( $mode == 1 ) { // safe mode
$time = 300;
$limit = 7;
$codes = array( 404, 500 );
}
$code = http_response_code();
if ( $code < 400 || ( $codes && ! in_array( $code, $codes ) ) ) {
return;
}
$go = false;
if ( cerber_is_http_post() ) {
$go = true;
}
if ( ! $go && cerber_get_uri_script() ) {
$go = true;
}
if ( ! $go ) {
if ( $mode == 1 ) {
if ( cerber_get_non_wp_fields() ) {
$go = true;
}
}
else {
if ( ! empty( $_GET ) ) {
$go = true;
}
}
}
if ( ! $go && cerber_is_rest_url() ) {
$go = true;
}
if ( ! $go ) {
return;
}
$ip = cerber_get_remote_ip();
cerber_db_query( 'INSERT INTO ' . CERBER_QMEM_TABLE . ' (ip, http_code, stamp)
VALUES ("' . $ip . '",' . intval( http_response_code() ) . ',' . time() . ')' );
if ( ! $cerber_blocked ) {
$t = time() - $time;
$c = cerber_db_get_var( 'SELECT COUNT(ip) FROM ' . CERBER_QMEM_TABLE . ' WHERE ip = "' . $ip . '" AND stamp > ' . $t );
if ( $c >= $limit ) {
cerber_soft_block_add( $ip, 711 );
$cerber_status = 18;
}
}
}
function cerber_catch_error( $errno, $errstr = null, $errfile = null, $errline = null ) {
global $cerber_php_errors;
if ( ! $errno ) {
return false;
}
if ( ! isset( $cerber_php_errors ) || ! is_array( $cerber_php_errors ) ) {
$cerber_php_errors = array();
}
$cerber_php_errors[] = array( $errno, $errstr, $errfile, $errline );
return false;
}
function cerber_traffic_log(){
global $cerber_php_errors, $cerber_db_errors, $wp_query, $wp_cerber_user_id, $wp_cerber_start_stamp, $blog_id;
static $logged = false;
if ( $logged || cerber_is_cloud_request() ) {
return;
}
$wp_cerber = get_wp_cerber();
$wp_type = 700;
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
/*
if ( isset( $_POST['action'] ) && $_POST['action'] == 'heartbeat' ) {
return;
}*/
$wp_type = 500;
}
elseif ( is_admin() ) {
$wp_type = 501;
}
elseif ( cerber_is_wp_cron() ) {
$wp_type = 502;
}
elseif ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
$wp_type = 515;
}
elseif ( cerber_is_rest_url() ) {
$wp_type = 520;
}
// Public part starts with 600
elseif ( $wp_query && is_object( $wp_query ) ) {
$wp_type = 600;
if ( $wp_query->is_singular ) {
$wp_type = 601;
}
elseif ( $wp_query->is_tag ) {
$wp_type = 603;
}
elseif ( $wp_query->is_category ) {
$wp_type = 604;
}
elseif ( $wp_query->is_search ) {
$wp_type = 605;
}
}
if ( function_exists( 'http_response_code' ) ) { // PHP >= 5.4.0, PHP 7
$http_code = http_response_code();
}
else {
$http_code = 200;
if ( $wp_type > 600 ) {
if ( $wp_query->is_404 ) {
$http_code = 404;
}
}
}
$user_id = 0;
if ( function_exists( 'get_current_user_id' ) ) {
$user_id = get_current_user_id();
}
if ( ! $user_id && $wp_cerber_user_id ) {
$user_id = absint( $wp_cerber_user_id );
}
if ( ! cerber_to_log( $wp_type, $http_code, $user_id ) ) {
return;
}
$logged = true;
$ua = '';
if ( ! empty( $_SERVER['HTTP_USER_AGENT'] ) ) {
$ua = substr ($_SERVER['HTTP_USER_AGENT'], 0, 1000);
}
$bot = cerber_is_crawler( $ua );
if ( $bot && crb_get_settings( 'tinocrabs' ) ) {
return;
}
$ip = $wp_cerber->getRemoteIp();
$ip_long = 0;
if ( cerber_is_ipv4( $ip ) ) {
$ip_long = ip2long( $ip );
}
$wp_id = 0;
if ( $wp_query && is_object( $wp_query ) ) {
$wp_id = absint( $wp_query->get_queried_object_id() );
}
$session_id = $wp_cerber->getSessionID();
if ( is_ssl() ) {
$scheme = 'https';
}
else {
$scheme = 'http';
}
$uri = $scheme . '://'. $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
$method = preg_replace( '/[^\w]/', '', $_SERVER['REQUEST_METHOD'] );
// Request fields
$fields = '';
if ( crb_get_settings( 'tifields' ) ) {
$fields = array();
if ( ! empty( $_POST ) ) {
$fields[1] = cerber_prepare_fields( cerber_mask_fields( (array) $_POST ) );
}
if ( ! empty( $_GET ) ) {
$fields[2] = cerber_prepare_fields( (array) $_GET );
}
if ( ! empty( $_FILES ) ) {
$fields[3] = $_FILES;
}
if ( ! empty( $fields ) ) {
$fields = serialize( $fields );
}
else {
$fields = '';
}
}
// Extra request details
$details = array();
$details[1] = $ua;
if ( ! empty( $_SERVER['HTTP_REFERER'] ) ) {
//$ref = mb_substr( $_SERVER['HTTP_REFERER'], 0, 1048576 ); // 1 Mb for ASCII
$details[2] = filter_var( $_SERVER['HTTP_REFERER'], FILTER_SANITIZE_URL );
}
/*
if ( ! empty( $_FILES ) ) {
$details[3] = $_FILES;
}*/
if ( $wp_type == 605 && ! empty( $_GET['s'] ) ) {
$details[4] = $_GET['s'];
}
if ( $wp_type == 515 ) {
// TODO: add a setting to enable it because there is a user/password in the php://input
//$details[5] = file_get_contents('php://input');
}
if ( crb_get_settings( 'tihdrs' ) ) {
$hds = getallheaders();
unset( $hds['Cookie'] );
$details[6] = $hds;
}
if ( crb_get_settings( 'tisenv' ) ) {
$srv = $_SERVER;
unset( $srv['HTTP_COOKIE'] );
$details[7] = $srv;
}
if ( crb_get_settings( 'ticandy' ) && ! empty( $_COOKIE ) ) {
$details[8] = $_COOKIE;
}
if ( !empty( $details ) ) {
$details = cerber_prepare_fields( $details );
$details = serialize($details);
}
else {
$details = '';
}
// Software errors
$php_err = '';
if ( crb_get_settings( 'tiphperr' ) ) {
if ( $cerber_php_errors && is_array( $cerber_php_errors ) ) {
//$err_not = array( E_NOTICE, E_WARNING );
$i = 0;
foreach ( $cerber_php_errors as $key => $e ) {
if ( $e[0] == E_NOTICE ) {
//unset( $cerber_php_errors[ $key ] );
}
else {
$i ++;
}
if ( $i > 25 ) { // Save no more errors
break;
}
}
if ( $cerber_php_errors ) {
$cerber_php_errors = array_values( $cerber_php_errors );
$cerber_php_errors = array_slice( $cerber_php_errors, 0, 25 );
$php_err = serialize( $cerber_php_errors );
}
}
}
// Timestamps
if ( ! empty( $wp_cerber_start_stamp ) && is_numeric( $wp_cerber_start_stamp ) ) {
$start = (float) $wp_cerber_start_stamp; // define this variable: $wp_cerber_start_stamp = microtime( true ); in wp-config.php
}
else {
$start = cerber_request_time();
}
$processing = (int) ( 1000 * ( microtime( true ) - $start ) );
$uri = cerber_real_escape( $uri );
$fields = cerber_real_escape( $fields );
$details = cerber_real_escape( $details );
$php_err = cerber_real_escape( $php_err );
$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, php_errors )
VALUES ("' . $ip . '", ' . $ip_long . ',"' . $uri . '","' . $fields . '","' . $details . '", "' . $session_id . '", ' . $user_id . ', ' . $start . ',' . $processing . ', "' . $method . '", ' . $http_code . ',' . $wp_id . ', ' . $wp_type . ', ' . $bot . ', ' . absint( $blog_id ) . ',"' . $php_err . '")';
$ret = cerber_db_query( $query );
if ( ! $ret ) {
//cerber_diag_log( print_r( $cerber_db_errors, 1 ) );
// mysqli_error($wpdb->dbh);
// TODO: Daily software error report
/*
echo mysqli_sqlstate($wpdb->dbh);
echo $wpdb->last_error;
echo "<p>\n";
echo $uri;
echo "<p>\n";
echo '<p>ERR '.$query.$wpdb->last_error;
echo '<p>'.$wpdb->_real_escape( $uri );
*/
}
}
/**
* To log or not to log current request?
*
* @param $wp_type integer
* @param $http_code integer
* @param $user_id integer
*
* @return bool
* @since 6.0
*/
function cerber_to_log( $wp_type, $http_code, $user_id ) {
global $cerber_logged, $cerber_blocked, $wp_cerber;
if ( nexus_is_valid_request() ) {
return false;
}
$mode = crb_get_settings( 'timode' );
if ( $mode == 0 ) {
return false;
}
if ( $mode == 2 ) {
if ( $wp_type < 515 ) { // Pure admin requests
if ( $wp_type < 502 && ! $user_id ) { // @since 6.3
return true;
}
//if ( $wp_type == 500 && 'admin-ajax.php' != cerber_get_uri_script() ) { // @since 7.8
if ( $wp_type == 500 && ! CRB_Request::is_script( '/wp-admin/admin-ajax.php' ) ) { // @since 7.9.1
return true;
}
return false;
}
return true;
}
// Smart mode ---------------------------------------------------------
if ( ! empty( $cerber_logged ) ) {
$tmp = $cerber_logged;
unset( $tmp[7] );
unset( $tmp[51] );
if ( ! empty( $tmp ) ) {
return true;
}
}
if ( $cerber_blocked ) {
return true;
}
if ( $wp_type < 515 ) {
if ( $wp_type < 502 && ! $user_id ) { // @since 6.3
if ( ! empty( $_GET ) || ! empty( $_POST ) || ! empty( $_FILES ) ) {
return true;
}
}
if ( $wp_type == 500 && ! CRB_Request::is_script( '/wp-admin/admin-ajax.php' ) ) { // @since 7.8
return true;
}
return false;
}
if ( $http_code >= 400 ||
$wp_type < 600 ||
$user_id ||
! empty( $_POST ) ||
! empty( $_FILES ) ||
isset( $_GET['s'] )
|| cerber_get_non_wp_fields() ) {
return true;
}
if ( cerber_is_http_post()
|| cerber_get_uri_script() ) {
return true;
}
return false;
}
/**
* Mask sensitive request fields before saving in DB (avoid information leaks)
*
* @param $fields array
*
* @return array
* @since 6.0
*/
function cerber_mask_fields( $fields ) {
$to_mask = array( 'pwd', 'pass', 'password', 'password_1', 'password_2', 'cerber-cloud-key' );
if ( $list = (array) crb_get_settings( 'timask' ) ) {
$to_mask = array_merge( $to_mask, $list );
}
foreach ( $to_mask as $mask_field ) {
if ( ! empty( $fields[ $mask_field ] ) ) {
$fields[ $mask_field ] = str_pad( '', mb_strlen( $fields[ $mask_field ] ), '*' );
}
}
return $fields;
}
/**
* Recursive prepare values in array for inserting into DB
*
* @param $list
*
* @return mixed
* @since 6.0
*/
function cerber_prepare_fields( $list ) {
foreach ( $list as &$field ) {
if ( is_array( $field ) ) {
$field = cerber_prepare_fields( $field );
}
else {
if ( ! $field ) {
$field = '';
}
else {
$field = mb_substr( $field, 0, 1048576 ); // 1 Mb for ASCII
}
}
}
$list = stripslashes_deep( $list );
return $list;
}
/**
* Return non WordPress public query $_GET fields (parameters)
*
* @param array $fields An associative array field => value to check
*
* @return array
* @since 6.0
*/
function cerber_get_non_wp_fields( $fields = array() ) {
global $wp_query;
static $result;
if ( isset( $result ) ) {
return $result;
}
if ( empty( $fields ) ) {
$get_keys = array_keys( $_GET );
}
else {
$get_keys = array_keys( $fields );
}
if ( empty( $get_keys ) ) {
$result = array();
}
if ( is_object( $wp_query ) ) {
$keys = $wp_query->fill_query_vars( array() );
}
elseif ( class_exists( 'WP_Query' ) ) {
$tmp = new WP_Query();
$keys = $tmp->fill_query_vars( array() );
}
else {
$keys = array();
}
$wp_keys = array_keys( $keys ); // WordPress GET fields for frontend
// Some well-known fields
$wp_keys[] = 'redirect_to';
$wp_keys[] = 'reauth';
$wp_keys[] = 'action';
$wp_keys[] = '_wpnonce';
$wp_keys[] = 'loggedout';
$wp_keys[] = 'doing_wp_cron';
// WP Customizer fields
$wp_keys = array_merge( $wp_keys, array(
'nonce',
'_method',
'wp_customize',
'changeset_uuid',
'customize_changeset_uuid',
'customize_theme',
'theme',
'customize_messenger_channel',
'customize_autosaved'
) );
$result = array_diff( $get_keys, $wp_keys );
if ( ! $result ) {
$result = array();
}
return $result;
}
/**
*
* @since 6.0
*/
function cerber_beast() {
global $cerber_status;
if ( is_admin()
|| cerber_is_wp_cron()
|| ( defined( 'WP_CLI' ) && WP_CLI )
) {
return;
}
$wp_cerber = get_wp_cerber();
$wp_cerber->CheckProhibitedURI();
// TI --------------------------------------------------------------------
if ( ! $ti_mode = crb_get_settings( 'tienabled' ) ) {
return;
}
// White list by IP
if ( crb_get_settings( 'tiipwhite' ) && crb_acl_is_white() ) {
return; // @since 7.9
}
// White list by URI
//$uri = cerber_purify_uri();
$uri = CRB_Request::URI();
if ( $tiwhite = crb_get_settings( 'tiwhite' ) ) {
foreach ( (array) $tiwhite as $item ) {
if ( substr( $item, 0, 1 ) == '{' && substr( $item, - 1 ) == '}' ) {
$pattern = '/' . substr( $item, 1, - 1 ) . '/i';
if ( @preg_match( $pattern, $uri ) ) {
return;
}
}
elseif ( $item == $uri ) {
return;
}
}
}
// Step one
$wp_cerber->InspectRequest();
// Step two
//$uri_script = cerber_get_uri_script();
$uri_script = CRB_Request::script();
if ( $uri_script && $script_filename = cerber_script_filename() ) {
// Scanning for executable scripts?
if ( ! cerber_script_exists( $uri ) && ! cerber_is_login_request() ) {
$cerber_status = 19;
cerber_log( 55 );
if ( $ti_mode > 1 ) {
cerber_soft_block_add( null, 708 );
}
cerber_forbidden_page();
}
// Direct access to a PHP script
$deny = false;
if ( crb_acl_is_black() ) {
$deny = true;
$cerber_status = 14;
}
//elseif ( ! in_array( $uri_script, cerber_get_wp_scripts() ) ) {
elseif ( ! CRB_Request::is_script( cerber_get_wp_scripts() ) ) {
if ( ! cerber_is_allowed() ) {
$deny = true;
$cerber_status = 13;
}
elseif ( lab_is_blocked( null, true ) ) {
$deny = true;
$cerber_status = 15;
}
}
if ( $deny ) {
cerber_log( 50 );
cerber_forbidden_page();
}
}
// Step three
cerber_screen_request_fields();
// Step four
cerber_inspect_uploads();
}
/**
* Inspects POST & GET fields
*
*/
function cerber_screen_request_fields(){
global $cerber_in_context;
$white = array();
$found = false;
if ( ! empty( $_GET ) ) {
$cerber_in_context = 1;
$found = cerber_inspect_array( $_GET, array( 's' ) );
}
if ( ! empty( $_POST ) && ! $found ) {
if ( CRB_Request::is_script( '/' . WP_COMMENT_SCRIPT ) ) {
$white = array( 'comment' );
}
$cerber_in_context = 2;
$found = cerber_inspect_array( $_POST, $white );
}
if ( $found ) {
cerber_log( $found );
cerber_soft_block_add( null, 709);
cerber_forbidden_page();
}
}
/**
* Recursively inspects values in a given multi-dimensional array
*
* @param array $array
* @param array $white A list of elements to skip
*
* @return bool|int
*/
function cerber_inspect_array( &$array, $white = array() ) {
global $cerber_status;
static $rec_limit = null;
if ( ! $array ) {
return false;
}
if ( $rec_limit === null ) {
$rec_limit = CERBER_CIREC_LIMIT;
}
else {
$rec_limit --;
if ( $rec_limit <= 0 ) {
$rec_limit = null;
$cerber_status = 20;
return 100;
}
}
foreach ( $array as $key => $value ) {
if ( in_array( $key, $white ) ) {
continue;
}
if ( is_array( $value ) ) {
$found = cerber_inspect_array( $value );
}
else {
$found = cerber_inspect_value( $value, true );
}
if ( $found ) {
return $found;
}
}
$rec_limit ++;
return false;
}
function cerber_inspect_value( &$value = '', $reset = false ) {
global $cerber_status, $crb_x64;
static $rec_limit = null; // Real recursion limit
if ( ! $value || is_numeric( $value ) ) {
return false;
}
if ( $reset ) {
$rec_limit = null;
}
if ( $rec_limit === null ) {
$rec_limit = CERBER_CIREC_LIMIT;
}
else {
$rec_limit --;
if ( $rec_limit <= 0 ) {
$rec_limit = null;
$cerber_status = 21;
return 100;
}
}
$found = false;
if ( $varbyref = cerber_is_base64_encoded( $value ) ) {
$found = cerber_inspect_value( $varbyref );
}
else {
$parsed = cerber_detect_php_code( $value );
if ( ! empty( $parsed[0] ) ) {
$cerber_status = 22;
$found = 100;
}
elseif ( ! empty( $parsed[1] ) ) {
foreach ( $parsed[1] as $string ) {
$found = cerber_inspect_value( $string );
if ( $found ) {
break;
}
}
}
if ( ! $found && cerber_detect_other_code( $value ) ) {
$cerber_status = 23;
$found = 100;
}
if ( ! $found && cerber_detect_js_code( $value ) ) {
$cerber_status = 24;
$found = 100;
}
}
$rec_limit ++;
return $found;
}
/**
* @param $value string
*
* @return array A list of suspicious code patterns
*/
function cerber_detect_php_code( &$value ) {
static $list;
if ( ! $list ) {
$list = cerber_get_php_unsafe();
}
$ret = array( array(), array() );
$code_tokens = array( T_STRING, T_EVAL );
$clean = preg_replace( "/[\r\n\s]+/", '', cerber_remove_comments( $value ) );
if ( $tokens = @token_get_all( '<?php ' . $clean ) ) {
foreach ( $tokens as $token ) {
if ( ! is_array( $token ) ) {
continue;
}
if ( in_array( $token[0], $code_tokens ) && isset( $list[ $token[1] ] ) ) {
if ( preg_match( '/' . $token[1] . '\((?!\)).+\)/i', $clean ) ) {
$ret[0] = array( $token[0], $list[ $token[1] ] );
break;
}
}
elseif ( $token[0] == T_CONSTANT_ENCAPSED_STRING ) {
$string = trim( $token[1], '\'"' );
if ( ! $string || is_numeric( $string ) ) {
continue;
}
$ret[1][] = $string;
}
}
}
return $ret;
}
function cerber_detect_other_code( &$value ) {
global $cerber_in_context;
//static $sql = array( 'information_schema.', 'xp_cmdshell', 'FROM_BASE64', '@@' );
$co = ( isset( $cerber_in_context ) ) ? $cerber_in_context : 0;
$score = 0;
$str = $value;
if ( $co > 0 ) {
$str = preg_replace( '#/\*(?:[^*]*(?:\*(?!/))*)*\*/#', '', $str ); // Remove comments
if ( $co == 1 ) {
if ( strlen( $value ) != strlen( $str ) ) {
$score ++;
}
}
}
if ( preg_match( '/\b(?:SELECT|INSERT|UPDATE|DELETE)\b/i', $str ) ) { // SQL?
$score ++;
$p = stripos( $str, 'UNION' );
if ( $p !== false ) {
$score ++;
if ( $co == 1 ) {
return true;
}
}
if ( preg_match( '/\b(?:information_schema|FROM_BASE64|wp_users|xp_cmdshell|LOAD_FILE)\b/i', $value ) ) {
return true;
}
if ( $co < 1 ) {
return false;
}
// $_GET & $_POST
if ( preg_match( '/\b(?:name_const|unhex)\b/i', $value ) ) {
$score ++;
}
if ( $score > 3 ) {
return true;
}
$char = substr_count( strtoupper( $value ), 'CHAR' );
if ( $char > 1 ) {
return true;
}
$score += $char;
if ( $score > 3 ) {
return true;
}
}
return false;
}
/**
* Detects ob/fus/cated JS
*
* @param $val
*
* @return bool
*/
function cerber_detect_js_code( $val ) {
$val = trim( $val );
if ( empty( $val ) || is_numeric( $val ) ) {
return false;
}
$val = preg_replace( "/[\s]+/", '', $val );
if ( strlen( $val ) < 32 ) {
return false;
}
// HEX
if ( preg_match_all( '/(["\'])(\\\\x[0-9a-fA-F]{2})+?\1/m', $val, $matches ) ) {
$found = array_map( function ( $v ) {
return trim( $v, '\'"' );
}, $matches[0] );
$found = str_replace( '\x', '', $found );
// -- V2
/*
$pieces = array();
foreach ( $found as $str) {
echo $str.'-';
$hexs = str_split( $str, 2 );
$pieces[] = implode( '', array_map( function ( $v ) {
return chr( hexdec( $v ) );
}, $hexs ) );
}*/
// V1
$hexs = str_split( implode( '', $found ), 2 );
$decoded = implode( '', array_map( function ( $hex ) {
return chr( hexdec( $hex ) );
}, $hexs ) );
if ( preg_match( '/(fromCharCode|createElement|appendChild|script|eval|unescape|getElement|querySelector|XMLHttpRequest|FileSystemObject)/i', $decoded ) ) {
return true;
}
}
if ( preg_match_all( '/((?:\d|0x)[\da-fA-F]{1,4})\s*(?:,|\))/m', $val, $matches ) ) {
$decoded = cerber_fromcharcode( implode( ',', $matches[1] ) );
$p = cerber_get_js_patterns();
list ($xdata, $severity) = cerber_process_patterns( $decoded, $p );
if ( $xdata ) {
return true;
}
}
return false;
}
function cerber_process_patterns( $str, $patterns ) {
$xdata = array();
$severity = array();
foreach ( $patterns as $pa ) {
if ($pa[1] == 2) { // 2 = REGEX
$matches = array();
if ( preg_match_all( '/' . $pa[2] . '/i', $str, $matches, PREG_OFFSET_CAPTURE ) ) {
if ( ! empty( $pa['not_func'] ) && function_exists( $pa['not_func'] ) ) {
foreach ( $matches[0] as $key => $match ) {
if ( call_user_func( $pa['not_func'], $match[0] ) ) {
unset( $matches[0][ $key ] );
}
}
}
if ( ! empty( $pa['func'] ) && function_exists( $pa['func'] ) ) {
foreach ( $matches[0] as $key => $match ) {
if ( ! call_user_func( $pa['func'], $match[0] ) ) {
unset( $matches[0][ $key ] );
}
}
}
if ( ! empty( $matches[0] ) ) {
$xdata[] = array( 2, $pa[0], array_values( $matches[0] ) );
$severity[] = $pa[3];
}
}
}
else {
if ( false !== stripos( $str, $pa[2] ) ) {
$xdata[] = array( 2, $pa[0], array( array( $pa[2] ) ) );
$severity[] = $pa[3];
}
}
}
return array( $xdata, $severity );
}
function cerber_inspect_uploads() {
static $found = null;
if ( $found !== null ) {
return $found; // avoid double inspection
}
if ( empty( $_FILES ) ) {
return $found;
}
$files = array();
foreach ( $_FILES as $file ) {
if ( is_array( $file['tmp_name'] ) ) {
$files[] = array_merge( $files, $file['tmp_name'] );
}
else {
$files[] = $file['tmp_name'];
}
}
$found = false;
foreach ( $files as $file_name ) {
if ( $f = @fopen( $file_name, 'r' ) ) {
$str = @fread( $f, 100000 );
@fclose( $f );
if ( cerber_inspect_value( $str ) ) {
$found = 56;
if ( ! @unlink( $file_name ) ) {
// if a system doesn't permit us to delete the file in the tmp uploads folder
$target = cerber_get_the_folder() . 'must_be_deleted.tmp';
@move_uploaded_file( $file_name, $target );
@unlink( $target );
}
}
}
}
if ( $found ) {
cerber_log( $found );
cerber_soft_block_add( null, 710);
}
return $found;
}
function cerber_error_control() {
if ( crb_get_settings( 'nophperr' ) ) {
@ini_set( 'display_startup_errors', 0 );
@ini_set( 'display_errors', 0 );
}
}
// Menu routines ---------------------------------------------------------------
// Hide/show menu items in public
add_filter( 'wp_get_nav_menu_items', function ( $items, $menu, $args ) {
if ( is_admin() ) {
return $items;
}
$logged = is_user_logged_in();
foreach ( $items as $key => $item ) {
// For *MENU*CERBER* See cerber_nav_menu_box() !!!
if ( 0 === strpos( $item->attr_title, '*MENU*CERBER*' ) ) {
$menu_id = explode( '|', $item->attr_title );
switch ( $menu_id[1] ) {
case 'wp-cerber-login-url':
if ( $logged ) {
unset( $items[ $key ] );
}
break;
case 'wp-cerber-logout-url':
if ( ! $logged ) {
unset( $items[ $key ] );
}
break;
case 'wp-cerber-reg-url':
if ( $logged ) {
unset( $items[ $key ] );
}
break;
case 'wp-cerber-wc-login-url':
if ( $logged ) {
unset( $items[ $key ] );
}
break;
case 'wp-cerber-wc-logout-url':
if ( ! $logged ) {
unset( $items[ $key ] );
}
break;
}
}
}
return $items;
}, 10, 3 );
// Set actual URL for a menu item based on a special value in title attribute
add_filter( 'nav_menu_link_attributes', function ( $atts ) {
// For *MENU*CERBER* See cerber_nav_menu_box() !!!
if ( 0 === strpos( $atts['title'], '*MENU*CERBER*' ) ) {
$title = explode( '|', $atts['title'] );
$atts['title'] = '';
$url = '#';
// See cerber_nav_menu_items() !!!
switch ( $title[1] ) {
case 'wp-cerber-login-url':
$url = wp_login_url();
break;
case 'wp-cerber-logout-url':
$url = wp_logout_url();
break;
case 'wp-cerber-reg-url':
if ( get_option( 'users_can_register' ) ) {
$url = wp_registration_url();
}
break;
case 'wp-cerber-wc-login-url':
if ( class_exists( 'WooCommerce' ) ) {
$url = get_permalink( get_option( 'woocommerce_myaccount_page_id' ) );
}
break;
case 'wp-cerber-wc-logout-url':
if ( class_exists( 'WooCommerce' ) ) {
$url = wc_logout_url();
}
break;
}
$atts['href'] = $url;
}
return $atts;
}, 1 );
Cyb3r Drag0nz Team • Google Edition