'network-admin', 'id' => 'cerber_admin', 'title' => 'WP Cerber', 'href' => cerber_admin_link(), ); $wp_admin_bar->add_node( $args ); } /** * Wrapper for all admin pages * * @param $title string * @param $tabs array * @param $active_tab string * @param $renderer callable */ function cerber_show_admin_page( $title, $tabs = array(), $active_tab = null, $renderer = null ) { if ( ! $active_tab ) { $active_tab = crb_admin_get_tab( $tabs ); } if ( nexus_is_valid_request() ) { $title .= nexus_request_data()->at_site; } ?>

'; echo '
'; if ( $active_tab == 'help' ) { cerber_show_help(); } elseif ( is_callable( $renderer ) ) { call_user_func( $renderer, $active_tab ); } echo '
'; cerber_show_aside( $active_tab ); echo '
'; ?> deleteGarbage(); $per_page = ( ! empty( $args['per_page'] ) ) ? $args['per_page'] : crb_admin_get_per_page(); $limit = ( cerber_get_pn() - 1 ) * $per_page . ',' . $per_page; if ( $rows = cerber_db_get_results( 'SELECT * FROM ' . CERBER_BLOCKS_TABLE . ' ORDER BY block_until DESC LIMIT ' . $limit, MYSQL_FETCH_OBJECT ) ) { $total = cerber_blocked_num(); $list = array(); $base_url = cerber_admin_link( 'activity' ); $remove = cerber_admin_link( crb_admin_get_tab(), null, true ); foreach ( $rows as $row ) { $ip = '' . $row->ip . ''; $ip_info = cerber_get_ip_info( $row->ip, true ); if ( isset( $ip_info['hostname_html'] ) ) { $hostname = $ip_info['hostname_html']; } else { $ip_id = cerber_get_id_ip( $row->ip ); $hostname = '' . "\n"; } if ( lab_lab() ) { $single_ip = str_replace( '*', '1', $row->ip ); $country = '' . crb_country_html( null, $single_ip ); } else { $country = ''; } $list[] = '' . $ip . '' . $hostname . $country . '' . cerber_date( $row->block_until ) . '' . $row->reason . '' . __( 'Remove', 'wp-cerber' ) . ''; } $heading = array( __( 'IP', 'wp-cerber' ), __( 'Hostname', 'wp-cerber' ), __( 'Country', 'wp-cerber' ), __( 'Expires', 'wp-cerber' ), __( 'Reason', 'wp-cerber' ), __( 'Action', 'wp-cerber' ), ); if ( ! lab_lab() ) { unset( $heading[2] ); } $titles = '' . implode( '', $heading ) . ''; $table = '' . $titles . '' . $titles . '' . implode( '', $list ) . '
'; if ( empty( $args['no_navi'] ) ) { $table .= cerber_page_navi( $total, $per_page ); } //echo '

'.sprintf(__('Showing last %d records from %d','wp-cerber'),count($rows),$total).'

'; $showing = '

' . sprintf( __( 'Showing last %d records from %d', 'wp-cerber' ), count( $rows ), $total ) . '

'; $view = '

' . __( 'Hint', 'wp-cerber' ) . ': ' . __( 'To view activity, click on the IP', 'wp-cerber' ) . '

'; } else { $table = ''; $view = '

' . sprintf( __( 'No lockouts at the moment. The sky is clear.', 'wp-cerber' ) ) . '

'; } $ret = $table . '
' . $view . '
'; if ( $echo ) { echo $ret; } else { return $ret; } } function cerber_block_delete( $ip ) { $result = cerber_db_query( 'DELETE FROM ' . CERBER_BLOCKS_TABLE . ' WHERE ip = "' . cerber_real_escape( $ip ) . '"' ); crb_event_handler( 'ip_event', array( 'e_type' => 'unlocked', 'ip' => $ip, 'result' => $result ) ); return $result; } /* ACL management form in dashboard */ function cerber_acl_form(){ //echo '

'.__('White IP Access List','wp-cerber').'

'.__('These IPs will never be locked out','wp-cerber').' - Know more

'. echo '

' . __( 'White IP Access List', 'wp-cerber' ) . '

How Access Lists work  |  Import entries

' . cerber_acl_get_table('W'); //echo '

'.__('Black IP Access List','wp-cerber').'

'.__('Nobody can log in or register from these IPs','wp-cerber').' - Know more

'. echo '

'.__('Black IP Access List','wp-cerber').'

'. cerber_acl_get_table('B'); $user_ip = cerber_get_remote_ip(); $link = cerber_admin_link( 'activity' ) . '&filter_ip=' . $user_ip; $name = crb_country_html(null, $user_ip); echo '

'.__('Your IP','wp-cerber').': '.$user_ip.' '.$name.'

'; ?>
Use the following formats to add entries to the access lists
IPv4Single IPv4 address192.168.5.22
IPv4Range specified with hyphen (dash)192.168.1.45 - 192.168.22.165
IPv4Range specified with CIDR192.168.128.0/20
IPv4Subnet Class C specified with CIDR192.168.77.0/24
IPv4Any IPv4 address specified with CIDR0.0.0.0/0
IPv4Subnet Class C specified with wildcard192.168.77.*
IPv4Subnet Class B specified with wildcard192.168.*.*
IPv4Subnet Class A specified with wildcard192.*.*.*
IPv4Any IPv4 address specified with wildcard*.*.*.*
IPv6Single IPv6 address2001:0db8:85a3:0000:0000:8a2e:0370:7334
IPv6Range specified with hyphen (dash)2001:db8::ff00:41:0 - 2001:db8::ff00:41:12ff
IPv6Range specified with CIDR2001:db8::/46
IPv6Range specified with wildcard2001:db8::ff00:41:*
IPv6Any IPv6 address::/0
get_results( 'SELECT * FROM ' . CERBER_ACL_TABLE . " WHERE acl_slice = '.$acl_slice.' AND tag = '" . $tag . "' ORDER BY ip_long_begin, ip" ) ) { foreach ( $rows as $row ) { $links = ''; if ( ! $row->ver6 || cerber_is_ipv6( $row->ip ) ) { $links = '' . __( 'Check for activities', 'wp-cerber' ) . ' ' . cerber_traffic_link( array( 'filter_ip' => $row->ip ) ); } $list[] = '' . $row->ip . '' . $row->comments . '' . $links . ' ' . __( 'Remove', 'wp-cerber' ) . ' '; } $ret = '' . implode( '', $list ) . '
'; } else { $ret = '

' . __( 'List is empty', 'wp-cerber' ) . '

'; } $ret = '
' . $ret . '
' . cerber_nonce_field() . '
'; return $ret; } /* Handle actions with items in ACLs in the dashboard */ function cerber_acl_form_process( $post = array() ) { $tag = crb_array_get( $post, 'acl_tag', '', 'W|B' ); $ip = trim( crb_array_get( $post, 'add_acl' ) ); $ip = preg_replace( CRB_IP_NET_RANGE, ' ', $ip ); $ip = preg_replace( '/\s+/', ' ', $ip ); $comment = strip_tags( stripslashes( crb_array_get( $post, 'add_acl_comment', '' ) ) ); if ( $tag == 'B' ) { if ( ! cerber_can_be_listed( $ip ) ) { cerber_admin_notice( __( "You cannot add your IP address or network", 'wp-cerber' ) ); return; } $ok = sprintf( __( 'IP address %s has been added to Black IP Access List', 'wp-cerber' ), $ip ); } else { $ok = sprintf( __( 'IP address %s has been added to White IP Access List', 'wp-cerber' ), $ip ); } $result = cerber_acl_add( $ip, $tag, $comment ); if ( is_wp_error( $result ) ) { cerber_admin_notice( $result->get_error_message() ); } else { cerber_admin_message( $ok ); } return; } /* AJAX admin requests is landing here */ add_action('wp_ajax_cerber_ajax', 'cerber_admin_ajax'); function cerber_admin_ajax() { $go = cerber_check_ajax_permissions( false ); if ( $go === false ) { return false; } $admin = ( $go === true ) ? true : false; $response = array(); $request = crb_get_request_fields(); if ( $admin && ( $ip = crb_array_get( $request, 'acl_delete' ) ) ) { if ( cerber_acl_remove( $ip, crb_array_get( $request, 'slice' ) ) ) { $response['deleted_ip'] = $ip; } else { $response['error'] = 'Unable to delete the entry'; } } elseif ( isset( $request['crb_ajax_slug'] ) && isset( $request['crb_ajax_list'] ) ) { $slug = $request['crb_ajax_slug']; $response['slug'] = $slug; $list = array_unique( $request['crb_ajax_list'] ); /* $list = array_map(function ($ip_id){ return cerber_get_ip_id( $ip_id ); }, $list); $list = array_filter( $list, function ( $ip ) { if (filter_var( $ip, FILTER_VALIDATE_IP )){ return true; } });*/ $ip_list = array(); foreach ( $list as $ip_id ) { if ( $ip = filter_var( cerber_get_ip_id( $ip_id ), FILTER_VALIDATE_IP ) ) { $ip_list[ $ip_id ] = $ip; // Set elements for frontend $response['data'][ $ip_id ] = ''; } else { $response['data'][ $ip_id ] = '-'; } } switch ( $slug ) { case 'hostname': foreach ( $ip_list as $ip_id => $ip ) { $ip_info = cerber_get_ip_info( $ip ); $response['data'][ $ip_id ] = $ip_info['hostname_html']; } break; case 'country': if ( $country_list = lab_get_country( $ip_list, false ) ) { foreach ( $country_list as $ip_id => $country ) { if ( $country ) { $response['data'][ $ip_id ] = cerber_get_flag_html( $country, cerber_country_name( $country ) ); } else { $response['data'][ $ip_id ] = __( 'Unknown', 'wp-cerber' ); } } } break; } } elseif ( $admin && isset( $request['dismiss_info'] ) ) { if ( isset( $request['button_id'] ) && ( $request['button_id'] == 'lab_ok' || $request['button_id'] == 'lab_no' ) ) { lab_user_opt_in( $request['button_id'] ); } else { delete_site_option( 'cerber_admin_info' ); } } elseif ( $admin && ( $usearch = crb_array_get( $request, 'user_search' ) ) ) { $users = get_users( array( 'search' => '*' . esc_attr( $usearch ) . '*', ) ); $response = array(); if ( $users ) { foreach ( $users as $user ) { $data = get_userdata( $user->ID ); $response[] = array( 'id' => $user->ID, 'text' => crb_format_user_name( $data ) ); } } } echo json_encode( $response ); if ( ! nexus_is_valid_request() ) { wp_die(); } } add_action( 'wp_ajax_cerber_local_ajax', function () { check_ajax_referer( 'crb-ajax-admin', 'ajax_nonce' ); if ( ! is_super_admin() ) { wp_die( 'Oops! Access denied.' ); } $done = array(); switch ( crb_array_get( $_REQUEST, 'crb_ajax_do' ) ) { case 'bg_tasks_run': $done = cerber_bg_task_launcher( array_flip( crb_array_get( $_REQUEST, 'tasks', array() ) ) ); break; } echo json_encode( array( 'done' => $done ) ); exit; } ); /* * Retrieve extended IP information * @since 2.2 * */ function cerber_get_ip_info( $ip, $cache_only = false ) { $ip_id = cerber_get_id_ip( $ip ); $ip_info = @unserialize( get_transient( $ip_id ) ); // lazy way if ( $cache_only ) { return $ip_info; } if ( empty( $ip_info['hostname_html'] ) ) { $ip_info = array(); $hostname = @gethostbyaddr( $ip ); if ( ! $hostname ) { $hostname = __( 'unknown', 'wp-cerber' ); } $ip_info['hostname'] = $hostname; if ( ! filter_var( $hostname, FILTER_VALIDATE_IP ) ) { $hostname = str_replace( '.', '.', $hostname ); } $ip_info['hostname_html'] = $hostname; set_transient( $ip_id, serialize( $ip_info ), 24 * 3600 ); } return $ip_info; } /* Admin dashboard actions */ //add_action('admin_init','cerber_admin_request'); add_action( 'wp_loaded', function () { // 'wp_loaded' @since 5.6 if ( ! is_admin() ) { return; } cerber_admin_request(); } ); /** * @param bool $is_post * * @return mixed * */ function cerber_admin_request( $is_post = false ) { global $wpdb; if ( ! nexus_is_valid_request() && ! current_user_can( 'manage_options' ) ) { return; } $get = crb_get_query_params(); if ( ( ! $nonce = crb_array_get( $get, 'cerber_nonce' ) ) && ( ! $nonce = crb_get_post_fields( 'cerber_nonce' ) ) ) { return; } if ( ! wp_verify_nonce( $nonce, 'control' ) ) { return; } $post = crb_get_post_fields(); //$q = crb_admin_parse_query( array( 'cerber_admin_do', 'ip' ) ); $remove_args = array(); if ( cerber_is_http_get() ) { if ( ( $do = crb_array_get( $get, 'cerber_admin_do' ) ) ) { switch ( $do ) { case 'lockdel': $ip = crb_array_get( $get, 'ip' ); if ( cerber_block_delete( $ip ) ) { cerber_admin_message( sprintf( __( 'Lockout for %s was removed', 'wp-cerber' ), $ip ) ); $remove_args[] = 'ip'; } break; case 'testnotify': $t = crb_array_get( $get, 'type' ); $to = cerber_get_email( $t ); if ( cerber_send_email( $t ) ) { cerber_admin_message( __( 'Email has been sent to', 'wp-cerber' ) . ' ' . $to ); } else { cerber_admin_notice( __( 'Unable to send email to', 'wp-cerber' ) . ' ' . $to ); } $remove_args[] = 'type'; break; case 'subscribe': $m = crb_array_get( $get, 'mode' ); $mode = ( 'on' == $m ) ? 'on' : 'off'; crb_admin_alerts_do( $mode ); $remove_args[] = 'subscribe'; $remove_args[] = 'mode'; break; case 'nexus_set_role': nexus_enable_role(); wp_safe_redirect( cerber_admin_link( null, array( 'page' => 'cerber-nexus' ) ) ); exit(); break; case 'nexus_delete_slave': //nexus_delete_slave( cerber_get_get( 'site_id' ) ); wp_safe_redirect( cerber_admin_link( 'nexus_sites' ) ); exit(); break; case 'nexus_site_table': if ( cerber_get_bulk_action() ) { nexus_do_bulk(); } break; case 'scan_tegrity': $adm = crb_array_get( $get, 'crb_scan_adm' ); $file = crb_array_get( $get, 'crb_file_id' ); if ( in_array( $adm, array( 'delete', 'restore' ) ) ) { cerber_quarantine_do( $adm, crb_array_get( $get, 'crb_scan_id' ), crb_array_get( $get, 'crb_file_id' ) ); } elseif ( $adm == 'remove_ignore' ) { if ( crb_remove_ignore( $file ) ) { cerber_admin_message( 'The file has been removed from the list' ); } } $remove_args = array( 'crb_scan_adm', 'crb_scan_id', 'crb_file_id' ); break; case 'manage_diag_log': cerber_manage_diag_log( crb_array_get( $get, 'do_this' ) ); $remove_args[] = 'do_this'; break; case 'terminate_session': crb_admin_kill( crb_array_get( $get, 'id', null, '\w+' ), crb_array_get( $get, 'user_id' ) ); $remove_args = array( 'user_id', 'id' ); break; case 'export': if ( nexus_is_valid_request() ) { return crb_admin_get_tokenized_link(); } crb_admin_download_file( crb_array_get( $get, 'type' ) ); break; case 'load_defaults': cerber_load_defaults(); cerber_admin_message( __( 'Default settings have been loaded', 'wp-cerber' ) ); break; case 'clear_cache': CRB_Cache::reset(); break; default: return; } if ( nexus_is_valid_request() ) { return array( 'redirect' => true, 'remove_args' => $remove_args ); } else { cerber_safe_redirect( $remove_args ); } } // TODO: move to the switch above if ( cerber_get_get( 'citadel' ) == 'deactivate' ) { cerber_disable_citadel(); } elseif ( isset( $_GET['force_repair_db'] ) ) { cerber_create_db(); cerber_upgrade_db( true ); cerber_admin_message( 'Cerber\'s database tables have been repaired and upgraded' ); cerber_safe_redirect('force_repair_db'); } elseif ( $table = cerber_get_get( 'truncate', '[a-z_]+' ) ) { if ( 0 === strpos( $table, 'cerber_' ) ) { if ( $wpdb->query( 'TRUNCATE TABLE ' . $table ) ) { cerber_admin_message( 'Table ' . $table . ' has been truncated' ); } else { cerber_admin_notice( $wpdb->last_error ); } } cerber_safe_redirect( 'truncate' ); } elseif ( isset( $_GET['force_check_nodes'] ) ) { $best = lab_check_nodes( true ); cerber_admin_message( 'Cerber Lab\'s nodes has been checked. The closest node: ' . $best ); cerber_safe_redirect( 'force_check_nodes' ); } elseif ( isset( $_GET['clean_up_the_cache'] ) ) { lab_cleanup_cache(); cerber_admin_message( 'The cache has been cleaned up' ); cerber_safe_redirect( 'clean_up_the_cache' ); } } if ( cerber_is_http_post() ) { $redirect = false; if ( ( $do = crb_array_get( $post, 'cerber_admin_do' ) ) ) { switch ( $do ) { case 'update_role_policies': crb_admin_save_role_policies( $post ); $redirect = true; break; case 'update_geo_rules': crb_admin_save_geo_rules( $post ); break; case 'add2acl': cerber_acl_form_process( $post ); break; case 'add_slave': nexus_add_slave( crb_array_get( $post, 'new_slave_token' ) ); break; case 'crb_manage_sessions': if ( cerber_get_bulk_action() == 'bulk_session_terminate' ) { crb_admin_kill( crb_array_get( $post, 'ids', array(), '\w+' ) ); } elseif ( cerber_get_bulk_action() == 'bulk_block_user' ) { if ( ( $sids = crb_array_get( $post, 'ids', array(), '\w+' ) ) && ( $users = cerber_db_get_col( 'SELECT user_id FROM ' . cerber_get_db_prefix() . CERBER_USS_TABLE . ' WHERE wp_session_token IN ("' . implode( '","', $sids ) . '")' ) ) ) { array_walk( $users, 'cerber_block_user' ); } } break; case 'install_key': $lic = preg_replace( "/[^A-Z0-9]/i", '', crb_array_get( $post, 'cerber_license' ) ); if ( ( strlen( $lic ) == LAB_KEY_LENGTH ) || empty( $lic ) ) { lab_update_key( $lic ); if ( $lic ) { if ( lab_validate_lic() ) { cerber_admin_message( 'Great! You\'ve entered a valid license key.

Now, whenever you see a green shield icon in the top right-hand corner of any Cerber\'s admin page, it means the professional version works as intended and your website is protected by Cerber Cloud Protection.

Please use the client portal to manage subscriptions and get support at https://my.wpcerber.com

Thanks for being our client.

' ); } else { cerber_admin_notice( 'Error! You have entered an invalid or expired license key.' ); } } } break; } if ( $redirect ) { if ( nexus_is_valid_request() ) { // No redirection is needed so far, we use a second 'get_page' request //return array( 'redirect' => true, 'remove_args' => $remove_args ); } else { cerber_safe_redirect( $remove_args ); } } } } } function crb_admin_download_file( $t, $query = array() ) { switch ( $t ) { case 'activity': cerber_export_activity( $query ); break; case 'traffic': cerber_export_traffic( $query ); break; case 'get_diag_log': cerber_manage_diag_log( 'download' ); break; } } function cerber_safe_redirect( $rem_args ) { if ( empty( $rem_args ) ) { $rem_args = array(); } elseif ( ! is_array( $rem_args ) ) { $rem_args = array( $rem_args ); } // Most used common args to remove $rem_args = array_merge( $rem_args, array( '_wp_http_referer', '_wpnonce', 'cerber_nonce', 'ids', 'cerber_admin_do', 'action', 'action2' ) ); wp_safe_redirect( remove_query_arg( $rem_args ) ); exit(); // mandatory! } function crb_admin_get_tokenized_link() { if ( empty( nexus_request_data()->get_params ) ) { return false; } $key = str_shuffle( '_-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' ); if ( cerber_update_set( '_the_key_' . $key, array( 'query' => nexus_request_data()->get_params ), 1, true, time() + 60 ) ) { return array( 'redirect' => true, 'redirect_url' => home_url( '?cerber_magic_key=' . $key ) ); } cerber_admin_notice( 'Unable to generate a tokenized URL' ); return false; } function cerber_export_activity( $params = array() ) { crb_raise_limits( 512 ); $args = array( 'per_page' => 0 ); if ( $params ) { $args = array_merge( $params, $args ); } list( $query, $per_page, $falist, $ip, $filter_login, $user_id, $search, $sid, $in_url ) = cerber_activity_query( $args ); // We split into several requests to avoid PHP and MySQL memory limitations if ( defined( 'CERBER_EXPORT_CHUNK' ) && is_numeric( CERBER_EXPORT_CHUNK ) ) { $per_chunk = CERBER_EXPORT_CHUNK; } else { $per_chunk = 1000; // Rows per SQL request: a compromise between the size of SQL data at each iteration and script execution time } if ( ! $result = cerber_db_query( $query . ' LIMIT ' . $per_chunk ) ) { wp_die( 'Nothing to export' ); } $total = cerber_db_get_var( "SELECT FOUND_ROWS()" ); $info = array(); if ( $ip ) { $info[] = '"Filter by IP:","' . $ip . '"'; } if ( $user_id ) { $user = get_userdata( $user_id ); $info[] = '"Filter by user:","' . $user->display_name . '"'; } if ( $search ) { $info[] = '"Search results for:","' . $search . '"'; } $heading = array( __( 'IP Address', 'wp-cerber' ), __( 'Date', 'wp-cerber' ), __( 'Event', 'wp-cerber' ), __( 'Additional Details', 'wp-cerber' ), __( 'Local User', 'wp-cerber' ), __( 'User login', 'wp-cerber' ), __( 'User ID', 'wp-cerber' ), __( 'Username', 'wp-cerber' ), 'Unix Timestamp', 'Request ID', 'URL', ); cerber_send_csv_header( 'wp-cerber-activity', $total, $heading, $info ); $labels = cerber_get_labels( 'activity' ); $status = cerber_get_labels( 'status' ) + cerber_get_reason(); $placeholder = array( 0, '', '', '', '' ); $i = 0; do { while ( $row = mysqli_fetch_object( $result ) ) { $values = array(); if ( ! empty( $row->details ) ) { $details = explode( '|', $row->details ); } else { $details = $placeholder; } $values[] = $row->ip; $values[] = cerber_date( $row->stamp ); $values[] = $labels[ $row->activity ]; $s = $details[0]; $values[] = ( isset( $status[ $s ] ) ) ? $status[ $s ] : ''; $values[] = $row->display_name; $values[] = $row->ulogin; $values[] = $row->user_id; $values[] = $row->user_login; $values[] = $row->stamp; $values[] = $row->session_id; $values[] = $details[4]; cerber_send_csv_line( $values ); } mysqli_free_result( $result ); $i ++; $offset = $per_chunk * $i; } while ( ( $result = cerber_db_query( $query . ' LIMIT ' . $offset . ', ' . $per_chunk ) ) && $result->num_rows ); exit; } function cerber_send_csv_header( $f_name, $total, $heading = array(), $info = array() ) { $fname = $f_name . '.csv'; //$fname = rawurlencode( $f_name ) . '.csv'; // encode non-ASCII symbols //@ob_clean(); // This trick is crucial for some servers/environments (IIS) //header( "Content-Type: application/octet-stream" ); //header( "Content-Disposition: attachment; filename*=UTF-8''{$fname}" ); crb_file_headers( $fname ); $info[] = '"Generated by:","WP Cerber Security ' . CERBER_VER . '"'; $info[] = '"Website:","' . get_option( 'blogname' ) . '"'; $info[] = '"Date:","' . cerber_date( time() ) . '"'; $info[] = '"Rows in this file:","' . $total . '"'; echo implode( "\r\n", $info ) . "\r\n\r\n"; foreach ( $heading as &$item ) { $item = '"' . str_replace( '"', '""', trim( $item ) ) . '"'; } echo implode( ',', $heading ) . "\r\n"; } function cerber_send_csv_line( $values ) { foreach ( $values as &$value ) { $value = '"' . str_replace( '"', '""', trim( $value ) ) . '"'; } $line = implode( ',', $values ) . "\r\n"; echo $line; } function crb_admin_quick_nav( $context = '' ) { $ac = cerber_admin_link( 'activity' ); $links = array(); $links[] = array( $ac, __( 'View all', 'wp-cerber' ) ); $labels = cerber_get_labels( 'activity' ); $set = array( 5 ); foreach ( $set as $item ) { //$links[] = array( cerber_admin_link( 'activity' ) . '&filter_activity=' . $item, $labels[ $item ] ); $links[] = array( cerber_activity_link( array( $item ) ), $labels[ $item ] ); } //$links[] = array( cerber_activity_link( array( 2 ) ), __( 'User registered', 'wp-cerber' ) ); $links[] = array( cerber_activity_link( array( 1, 2 ) ), __( 'New users', 'wp-cerber' ) ); /*$links[] = array( cerber_activity_link( crb_get_activity_set( 'suspicious' ) ), __( 'Suspicious activity', 'wp-cerber' ) );*/ $links[] = array( $ac . '&filter_set=1', __( 'Suspicious activity', 'wp-cerber' ) ); $links[] = array( cerber_activity_link( array( 10, 11 ) ), __( 'IP blocked', 'wp-cerber' ) ); $links[] = array( $ac . '&filter_user=*', __( 'Logged in users', 'wp-cerber' ) ); $links[] = array( $ac . '&filter_user=0', __( 'Not logged in visitors', 'wp-cerber' ) ); if ( ! $context ) { $links[] = array( $ac . '&filter_user=' . get_current_user_id(), __( 'My activity', 'wp-cerber' ) ); } $ret = ''; foreach ( $links as $link ) { $ret .= '' . $link[1] . ' '; } return '
' . $ret . '
'; } /* * Display activities in the WP Dashboard * * */ function cerber_show_activity( $args = array(), $echo = true ) { global $crb_ajax_loader; $labels = cerber_get_labels( 'activity' ); $status_labels = cerber_get_labels( 'status' ) + cerber_get_reason(); $base_url = cerber_admin_link( 'activity' ); $export_link = ''; $ret = ''; list( $query, $per_page, $falist, $filter_ip, $filter_login, $user_id, $search, $sid, $in_url ) = cerber_activity_query( $args ); $sname = ''; $info = ''; if ( $filter_ip ) { $info .= cerber_ip_extra_view( $filter_ip ); } if ( $user_id ) { list( $sname, $tmp ) = cerber_user_extra_view( $user_id ); $info .= $tmp; } $user_cache = array(); //if ( $rows = $wpdb->get_results( $query ) ) { if ( $rows = cerber_db_get_results( $query, MYSQL_FETCH_OBJECT ) ) { $total = cerber_db_get_var( "SELECT FOUND_ROWS()" ); $tbody = ''; $roles = wp_roles()->roles; $country = ''; $geo = lab_lab(); foreach ( $rows as $row ) { $ip_id = cerber_get_id_ip( $row->ip ); $activity = '' . $labels[ $row->activity ] . ''; /* if ($row->activity == 50 ) { $activity .= ' '.htmlspecialchars($row->user_login).''; }*/ if ( empty( $args['no_details'] ) && $row->details ) { $details = explode( '|', $row->details ); if ( ! empty( $details[0] ) && isset( $status_labels[ $details[0] ] ) ) { $activity .= ' ' . $status_labels[ $details[0] ] . ''; } //elseif ($row->activity == 50 && $details[4]) $activity .= ' '.$details[4]; if ( isset( $details[4] ) && ( $row->activity < 10 || $row->activity > 12 ) ) { $activity .= '

URL: ' . str_replace( array( '-', '/' ), array( '-', '/' ), $details[4] ) . '

'; } } $activity = '
' . $activity . '
'; $name = crb_admin_get_user_cell( $row->user_id, $base_url ); //$ip = '' . $row->ip . ''; $username = '' . $row->user_login . ''; $ip_info = cerber_get_ip_info( $row->ip, true ); if ( isset( $ip_info['hostname_html'] ) ) { $hostname = $ip_info['hostname_html']; } else { $hostname = '' . "\n"; } /*$tip = ''; $acl = cerber_acl_check( $row->ip ); if ( $acl == 'W' ) { $tip = __( 'White IP Access List', 'wp-cerber' ); } elseif ( $acl == 'B' ) { $tip = __( 'Black IP Access List', 'wp-cerber' ); } if ( cerber_block_check( $row->ip ) ) { $block = ' color-blocked '; $tip .= ' ' . __( 'Locked out', 'wp-cerber' ); } else { $block = ''; }*/ if ( ! empty( $args['date'] ) && $args['date'] == 'ago' ) { $date = cerber_ago_time( $row->stamp ); } else { $date = '' . cerber_date( $row->stamp ) . ''; } if ( $geo ) { $country = '' . crb_country_html( $row->country, $row->ip ); } //$tbody .= '
' . $ip . '
' . $hostname . $country . '' . $date . '' . $activity . '' . $name . '' . $username . ''; $tbody .= '' . crb_admin_ip_cell( $row->ip, $base_url . '&filter_ip=' . $row->ip ) . '' . $hostname . $country . '' . $date . '' . $activity . '' . $name . '' . $username . ''; } $heading = array( '
' . __( 'IP Address', 'wp-cerber' ), __( 'Hostname', 'wp-cerber' ), __( 'Country', 'wp-cerber' ), __( 'Date', 'wp-cerber' ), __( 'Event', 'wp-cerber' ), __( 'Local User', 'wp-cerber' ), __( 'Username', 'wp-cerber' ) ); if ( ! $geo ) { unset( $heading[2] ); } $titles = '' . implode( '', $heading ) . ''; $table = '' . $titles . '' . $titles . '' . $tbody . '
'; if ( empty( $args['no_navi'] ) ) { $table .= cerber_page_navi( $total, $per_page ); } //$legend = '

'.sprintf(__('Showing last %d records from %d','wp-cerber'),count($rows),$total); if ( empty( $args['no_export'] ) ) { $export_link .= ' ' . __( 'Export', 'wp-cerber' ) . ''; //) ) . '"> ' . __( 'Export', 'wp-cerber' ) . ''; } } else { $table = '

' . __( 'No activity has been logged.', 'wp-cerber' ) . '

'; } if ( empty( $args['no_navi'] ) ) { $display = ( $sid || $in_url ) ? '' : 'display: none;'; /*$filters = '
' . crb_get_activity_dd() . cerber_select( 'filter_user', ( $user_id ) ? array( $user_id => $sname ) : array(), $user_id, 'crb-select2-ajax', '', false, esc_html__( 'Filter by registered user', 'wp-cerber' ), array( 'min_symbols' => 3 ) ) . ' More
';*/ $filters = '
' . crb_get_activity_dd() . cerber_select( 'filter_user', ( $user_id ) ? array( $user_id => $sname ) : array(), $user_id, 'crb-select2-ajax', '', false, esc_html__( 'Filter by registered user', 'wp-cerber' ), array( 'min_symbols' => 3 ) ) . '
[ More ]
'; $right_links = crb_admin_alert_link() . $export_link; $top_bar = '
' . $filters . '
' . $right_links . '

'; $ret = '
' . crb_admin_quick_nav(). $top_bar . $info . '
' . $ret; } $ret .= $table; if ( $echo ) { echo $ret; } else { return $ret; } } /** * Parse arguments and create SQL query for retrieving rows from activity log * * @param array $args Optional arguments to use them instead of using $_GET * * @return array * @since 4.16 */ function cerber_activity_query( $args = array() ) { global $wpdb; $ret = array_fill( 0, 9, '' ); $where = array(); $q = crb_admin_parse_query( array( 'filter_activity', 'filter_set', 'filter_ip', 'filter_login', 'filter_user', 'search_activity', 'filter_sid', 'search_url', 'filter_country', ), $args ); $falist = array(); if ( ! empty( $q->filter_set ) ) { switch ( $q->filter_set ) { case 1: $falist = crb_get_activity_set( 'suspicious' ); break; } } elseif ( $q->filter_activity ) { // Multiple activities can be requested this way: &filter_activity[]=11&filter_activity[]=7 if ( is_array( $q->filter_activity ) ) { $falist = array_filter( array_map( 'absint', $q->filter_activity ) ); } else { $falist = array( absint( $q->filter_activity ) ); // for further using in links } } if ( $falist ) { $where[] = 'log.activity IN (' . implode( ',', $falist ) . ')'; } $ret[2] = $falist; if ( $q->filter_ip ) { $range = cerber_any2range( $q->filter_ip ); if ( is_array( $range ) ) { $where[] = $wpdb->prepare( '(log.ip_long >= %d AND log.ip_long <= %d)', $range['begin'], $range['end'] ); } elseif ( cerber_is_ip_or_net( $q->filter_ip ) ) { $where[] = $wpdb->prepare( 'log.ip = %s', $q->filter_ip ); } else { $where[] = "ip = 'produce-no-result'"; } $ret[3] = preg_replace( CRB_IP_NET_RANGE, ' ', $q->filter_ip ); } if ( $q->filter_login ) { $where[] = $wpdb->prepare( 'log.user_login = %s', $q->filter_login ); $ret[4] = htmlspecialchars( $q->filter_login ); } /*$user_id = absint( $q->filter_user ); $ret[5] = $user_id; if ( $user_id ) { $where[] = 'log.user_id = ' . $user_id; }*/ if ( isset( $q->filter_user ) ) { if ( $q->filter_user == '*' ) { $where[] = 'log.user_id != 0'; $ret[5] = ''; } elseif ( is_numeric( $q->filter_user ) ) { $user_id = absint( $q->filter_user ); $where[] = 'log.user_id = ' . $user_id; $ret[5] = $user_id; } } if ( $q->search_activity ) { $search = stripslashes( $q->search_activity ); $ret[6] = htmlspecialchars( $search ); $search = '%' . $search . '%'; $escaped = cerber_real_escape( $search ); $w = array(); /* if ( $uids = cerber_db_get_col( 'SELECT user_id FROM ' . $wpdb->usermeta . ' WHERE (meta_key = "first_name" OR meta_key = "last_name" OR meta_key = "nickname") AND meta_value LIKE "' . cerber_real_escape( $search ) . '"' ) ) { $w[] = 'log.user_id IN (' . implode( ',', $uids ) . ')'; }*/ $w[] = 'log.user_login LIKE "' . $escaped . '"'; $w[] = 'log.ip LIKE "' . $escaped . '"'; $where[] = '(' . implode( ' OR ', $w ) . ')'; } if ( $q->filter_sid ) { $ret[7] = $sid = preg_replace( '/[^\w]/', '', $q->filter_sid ); $where[] = 'log.session_id = "' . $sid . '"'; } if ( $q->search_url ) { $search = stripslashes( $q->search_url ); $ret[8] = htmlspecialchars( $search ); $where[] = 'log.details LIKE "' . cerber_real_escape( '%' . $search . '%' ) . '"'; } if ( $q->filter_country ) { $country = substr( $q->filter_country, 0, 3 ); $ret[9] = htmlspecialchars( $country ); $where[] = 'log.country = "' . cerber_real_escape( $country ) . '"'; } $where = ( ! empty( $where ) ) ? 'WHERE ' . implode( ' AND ', $where ) : ''; // Limits, if specified $per_page = ( isset( $args['per_page'] ) ) ? absint( $args['per_page'] ) : crb_admin_get_per_page(); $ret[1] = $per_page; if ( $per_page ) { $limit = ' LIMIT ' . ( cerber_get_pn() - 1 ) * $per_page . ',' . $per_page; $ret[0] = 'SELECT SQL_CALC_FOUND_ROWS * FROM ' . CERBER_LOG_TABLE . " log {$where} ORDER BY stamp DESC {$limit}"; } else { $ret[0] = 'SELECT SQL_CALC_FOUND_ROWS log.*,u.display_name,u.user_login ulogin FROM ' . CERBER_LOG_TABLE . ' log LEFT JOIN '.$wpdb->users . " u ON (log.user_id = u.ID) {$where} ORDER BY stamp DESC"; // "ORDER BY" is mandatory! } return $ret; } function crb_admin_ip_cell( $ip, $ip_link = '', $text = '' ) { static $cache = array(); if ( isset( $cache[ $ip ] ) ) { return $cache[ $ip ]; } $tip = ''; $acl = cerber_acl_check( $ip ); if ( $acl == 'W' ) { $tip = __( 'White IP Access List', 'wp-cerber' ); } elseif ( $acl == 'B' ) { $tip = __( 'Black IP Access List', 'wp-cerber' ); } if ( cerber_block_check( $ip ) ) { $block = ' color-blocked '; $tip .= ' ' . __( 'Locked out', 'wp-cerber' ); } else { $block = ''; } if ( $ip_link ) { $ip = '' . $ip . ''; } $cache[ $ip ] = '
' . $ip . $text . '
'; //$cache[ $ip ] = '
' . $ip . $text . '
'; return $cache[ $ip ]; } /* * Additional information about IP address */ function cerber_ip_extra_view( $ip, $context = 'activity' ) { if ( ! $ip || ! filter_var( $ip, FILTER_VALIDATE_IP ) ) { return ''; } $ip_navs = ''; if ( $context == 'activity' ) { $ip_navs .= cerber_traffic_link( array( 'filter_ip' => $ip ) ); } else { $ip_navs .= ' ' . __( 'Check for activities', 'wp-cerber' ) . ''; } $acl = cerber_acl_check( $ip ); if ( $acl == 'W' ) { $ip_navs .= ' ' . __( 'White IP Access List', 'wp-cerber' ) . ' '; } elseif ( $acl == 'B' ) { $ip_navs .= ' ' . __( 'Black IP Access List', 'wp-cerber' ) . ' '; } if ( cerber_block_check( $ip ) ) { $ip_navs .= ' ' . __( 'Locked out', 'wp-cerber' ) . ' '; } // Filter activity by ... /*$labels = cerber_get_labels('activity'); foreach ($labels as $tag => $label) { //if (in_array($tag,$falist)) $links[] = ''.$label.''; $links[] = ''.$label.''; } $filters = implode(' | ',$links);*/ $whois = ''; $country = ''; $abuse = ''; $network = ''; $network_info = ''; $network_navs = ''; if ( crb_get_settings( 'ip_extra' ) ) { $ip_data = cerber_ip_whois_info( $ip ); if ( isset( $ip_data['error'] ) ) { $whois = '
' . $ip_data['error'] . '
'; } elseif ( isset( $ip_data['whois'] ) ) { $whois = '
' . $ip_data['whois'] . '
'; } if ( isset( $ip_data['country'] ) ) { $country = $ip_data['country']; } if ( ! empty( $ip_data['data']['abuse-mailbox'] ) ) { //$abuse = '

' . __( 'Abuse email:', 'wp-cerber' ) . ' ' . $ip_data['data']['abuse-mailbox'] . '

'; $abuse = __( 'Abuse email:', 'wp-cerber' ) . ' ' . $ip_data['data']['abuse-mailbox'] . ''; } if ( ! empty( $ip_data['data']['network'] ) ) { $network = $ip_data['data']['network']; $range = cerber_any2range( $network ); //$network_info = '

' . __( 'Network:', 'wp-cerber' ) . ' ' . $network . '   ' . __( 'Check for activities', 'wp-cerber' ) . ' ' . cerber_traffic_link( array( 'filter_ip' => $range['range'] ) ); $network_info = __( 'Network:', 'wp-cerber' ) . ' ' . $network; $network_navs = '' . __( 'Check for activities', 'wp-cerber' ) . ' ' . cerber_traffic_link( array( 'filter_ip' => $range['range'] ) ); } } $form = ''; if ( ! cerber_is_myip( $ip ) && ! cerber_acl_check( $ip ) ) { if ( $network ) { $net_button = ' '; $form = '

' . $net_button . cerber_nonce_field( 'control' ) . '
'; } $ip_info = '' . $ip . '' . $country . ''; $ret = '
' . $ip_info . '
' . $ip_navs . '
' . $network_info . '
' . $network_navs . '

' . $abuse . '

' . $form . '
'; return $ret . $whois; } /** * Additional information about user */ function cerber_user_extra_view( $user_id, $context = 'activity' ) { global $wpdb; $ret = ''; $class = ''; if ( $u = get_userdata( $user_id ) ) { if ( ! is_multisite() && $u->roles ) { $roles = array(); $wp_roles = wp_roles(); foreach ( $u->roles as $role ) { $roles[] = $wp_roles->roles[ $role ]['name']; } $roles = '' . implode( ', ', $roles ) . ''; } else { $roles = ''; } if ( ! nexus_is_valid_request() ) { $name = '' . $u->display_name . ''; } else { $name = $u->display_name; } $name = '' . $name . '

' . $roles . '

'; if ( $avatar = get_avatar( $user_id, 96 ) ) { $ret .= '
' . $avatar . '
'; } $user_info = array(); // Registered $reg = false; $time = strtotime( cerber_db_get_var( "SELECT user_registered FROM {$wpdb->users} WHERE id = " . $user_id ) ); if ( $time ) { $reg = cerber_auto_date( $time ); if ( $rm = get_user_meta( $user_id, '_crb_reg_', true ) ) { if ( $rm['IP'] ) { if ( $country = crb_country_html( null, $rm['IP'] ) ) { $reg .= '   ' . $country; } } } $user_info[] = array( __( 'Registered', 'wp-cerber' ), $reg ); } // Activated - BuddyPress if ( $log = cerber_get_log( array( 200 ), array( 'id' => $user_id ) ) ) { $acted = $log[0]; $activated = cerber_auto_date( $acted->stamp ); if ( $country = crb_country_html( null, $acted->ip ) ) { $activated .= '   ' . $country; } $user_info[] = array( __( 'Activated', 'wp-cerber' ), $activated ); } // Last seen $seen = ''; $s1 = $wpdb->get_row( 'SELECT stamp,ip FROM ' . CERBER_TRAF_TABLE . ' WHERE user_id = ' . $user_id . ' ORDER BY stamp DESC LIMIT 1' ); $s2 = $wpdb->get_row( 'SELECT stamp,ip FROM ' . CERBER_LOG_TABLE . ' WHERE user_id = ' . $user_id . ' ORDER BY stamp DESC LIMIT 1' ); $time1 = ( $s1 ) ? $s1->stamp : 0; $time2 = ( $s2 ) ? $s2->stamp : 0; $sn = ( $time1 < $time2 ) ? $s2 : $s1; if ( $sn ) { $seen = cerber_auto_date( $sn->stamp ); if ( $country = crb_country_html( null, $sn->ip ) ) { $seen .= '   ' . $country; } $user_info[] = array( __( 'Last seen', 'wp-cerber' ), $seen ); } if ( $usn = cerber_db_get_var( 'SELECT count(user_id) FROM ' . cerber_get_db_prefix() . CERBER_USS_TABLE . ' WHERE user_id = ' . $user_id ) ) { $user_info[] = array( __( 'Active sessions', 'wp-cerber' ), '' . $usn . ''); } //$ret .= '
' . $name . '

' . __( 'Registered', 'wp-cerber' ) . ': ' . $reg . '

' . $seen . $activated . $sessions . '
'; $summary = ''; foreach ( $user_info as $row ) { $summary .= '
' . implode( '
', $row ) . '
'; } $ret .= '
' . $name . $summary . '
'; if ( $context == 'activity' ) { $link = cerber_traffic_link( array( 'filter_user' => $user_id ) ); } else { $link = ' ' . __( 'Check for activities', 'wp-cerber' ) . ''; } if ( crb_is_user_blocked( $user_id ) ) { $class = 'crb-user-blocked'; } } if ( $ret ) { return array( crb_format_user_name( $u ), '
' . $ret . $link . '
' ); } return ''; } // Users ------------------------------------------------------------------------------------- add_filter('users_list_table_query_args' , function ($args) { if ( crb_get_settings( 'usersort' ) && empty( $args['orderby'] ) ) { $args['orderby'] = 'user_registered'; $args['order'] = 'desc'; } return $args; }); /* Add custom columns to the Users admin screen */ add_filter( 'manage_users_columns', function ( $columns ) { return array_merge( $columns, array( 'cbcc' => __( 'Comments', 'wp-cerber' ), 'cbla' => __( 'Last login', 'wp-cerber' ), 'cbfl' => '' . __( 'Failed login attempts', 'wp-cerber' ) . '', 'cbdr' => __( 'Registered', 'wp-cerber' ) ) ); } ); add_filter( 'manage_users_sortable_columns', function ( $sortable_columns ) { $sortable_columns['cbdr'] = 'user_registered'; return $sortable_columns; } ); /* Display custom columns on the Users screen */ add_filter( 'manage_users_custom_column' , function ($value, $column, $user_id) { global $wpdb, $user_ID; $ret = $value; switch ($column) { case 'cbcc' : // to get this work we need add filter 'preprocess_comment' if ($com = get_comments(array('author__in' => $user_id))) $ret = count($com); else $ret = 0; break; case 'cbla' : //$row = $wpdb->get_row('SELECT MAX(stamp) FROM '.CERBER_LOG_TABLE.' WHERE user_id = '.absint($user_id)); $row = $wpdb->get_row('SELECT * FROM '.CERBER_LOG_TABLE.' WHERE activity = 5 AND user_id = '.absint($user_id) . ' ORDER BY stamp DESC LIMIT 1'); if ($row) { $act_link = cerber_admin_link('activity'); if ( $country = crb_country_html( $row->country, $row->ip ) ) { $country = '
' . $country; } else { $country = ''; } $ret = ''.cerber_date($row->stamp).''.$country; } else $ret=__('Never','wp-cerber'); break; case 'cbfl' : $u = get_userdata( $user_id ); //$failed = $wpdb->get_var( 'SELECT COUNT(user_id) FROM ' . CERBER_LOG_TABLE . ' WHERE user_login = \'' . $u->user_login . '\' AND activity = 7 AND stamp > ' . ( time() - 24 * 3600 ) ); $failed = cerber_db_get_var( 'SELECT COUNT(user_id) FROM ' . CERBER_LOG_TABLE . ' WHERE user_login = "' . $u->user_login . '" AND activity = 7 AND stamp > ' . ( time() - 24 * 3600 ) ); if ( $failed ) { $act_link = cerber_admin_link( 'activity' ); $ret = '' . $failed . ''; } else { $ret = $failed; } break; case 'cbdr' : //$time = strtotime($wpdb->get_var("SELECT user_registered FROM $wpdb->users WHERE id = ".$user_id)); $time = strtotime( cerber_db_get_var( "SELECT user_registered FROM $wpdb->users WHERE id = " . $user_id ) ); if ($time < (time() - DAY_IN_SECONDS)){ $ret = cerber_date($time); } else { $ret = cerber_ago_time($time); } if ($rm = get_user_meta($user_id, '_crb_reg_', true)){ if ($rm['IP']) { $act_link = cerber_admin_link( 'activity', array( 'filter_ip' => $rm['IP'] ) ); $ret .= '
'.$rm['IP'].''; if ( $country = crb_country_html( null, $rm['IP'] ) ) { $ret .= '
' . $country; } } $uid = absint( $rm['user'] ); if ( $uid ) { //$name = $wpdb->get_var( 'SELECT meta_value FROM ' . $wpdb->usermeta . ' WHERE user_id = ' . $uid . ' AND meta_key = "nickname"' ); $name = cerber_db_get_var( 'SELECT meta_value FROM ' . $wpdb->usermeta . ' WHERE user_id = ' . $uid . ' AND meta_key = "nickname"' ); if (!$user_ID) { $user_ID = get_current_user_id(); } if ($user_ID == $uid){ $name .= ' (' . __( 'You', 'wp-cerber' ) . ')'; } $ret .= '
' . $name; } } break; } return $ret; }, 10, 3); /* Registering admin widgets */ if (!is_multisite()) add_action( 'wp_dashboard_setup', 'cerber_widgets' ); else add_action( 'wp_network_dashboard_setup', 'cerber_widgets' ); function cerber_widgets() { if (!current_user_can('manage_options')) return; if (current_user_can( 'manage_options')) { wp_add_dashboard_widget( 'cerber_quick', __('Cerber Quick View','wp-cerber'), 'cerber_quick_w'); } } /* Cerber Quick View widget */ function cerber_quick_w(){ $dash = cerber_admin_link(); $act = cerber_admin_link( 'activity' ); $traf = cerber_admin_link( 'traffic' ); $scanner = cerber_admin_link( 'scan_main' ); $acl = cerber_admin_link( 'acl' ); $sess = cerber_admin_link( 'sessions' ); $locks = cerber_admin_link( 'lockouts' ); $s_count = cerber_db_get_var('SELECT COUNT(DISTINCT user_id) FROM '. cerber_get_db_prefix() . CERBER_USS_TABLE ); $failed = cerber_db_get_var('SELECT count(ip) FROM '. CERBER_LOG_TABLE .' WHERE activity IN (7) AND stamp > '.(time() - 24 * 3600)); $failed_prev = cerber_db_get_var('SELECT count(ip) FROM '. CERBER_LOG_TABLE .' WHERE activity IN (7) AND stamp > '.(time() - 48 * 3600).' AND stamp < '.(time() - 24 * 3600)); $failed_ch = cerber_percent($failed_prev,$failed); $locked = cerber_db_get_var('SELECT count(ip) FROM '. CERBER_LOG_TABLE .' WHERE activity IN (10,11) AND stamp > '.(time() - 24 * 3600)); $locked_prev = cerber_db_get_var('SELECT count(ip) FROM '. CERBER_LOG_TABLE .' WHERE activity IN (10,11) AND stamp > '.(time() - 48 * 3600).' AND stamp < '.(time() - 24 * 3600)); $locked_ch = cerber_percent($locked_prev,$locked); //$lockouts = $wpdb->get_var('SELECT count(ip) FROM '. CERBER_BLOCKS_TABLE); $lockouts = cerber_blocked_num(); if ($last = cerber_db_get_var('SELECT MAX(stamp) FROM '.CERBER_LOG_TABLE.' WHERE activity IN (10,11)')) { $last = cerber_ago_time( $last ); } else $last = __('Never','wp-cerber'); $w_count = cerber_db_get_var('SELECT count(ip) FROM '. CERBER_ACL_TABLE .' WHERE tag ="W"' ); $b_count = cerber_db_get_var('SELECT count(ip) FROM '. CERBER_ACL_TABLE .' WHERE tag ="B"' ); if ( cerber_is_citadel() ) { $citadel = '' . __( 'active', 'wp-cerber' ) . ' (' . __( 'deactivate', 'wp-cerber' ) . ')'; } else { if ( crb_get_settings( 'citadel_on' ) && crb_get_settings( 'ciperiod' ) ) { $citadel = __( 'not active', 'wp-cerber' ); } else { $citadel = __( 'disabled', 'wp-cerber' ); } } echo '
'; echo ''; echo '
'.$failed.''.$failed_ch.'

'.__('failed attempts','wp-cerber').' '.__('in 24 hours','wp-cerber').'
('.__('view all','wp-cerber').')

'.$locked.''.$locked_ch.'

'.__('lockouts','wp-cerber').' '.__('in 24 hours','wp-cerber').'
('.__('view all','wp-cerber').')

'; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; $status = ( ! crb_get_settings( 'tienabled' ) ) ? ''.__('disabled','wp-cerber').'' : __('enabled','wp-cerber'); echo ''; $lab = lab_lab(); if ( $lab ) { $status = ( ! lab_is_cloud_ok() ) ? '' . __( 'no connection', 'wp-cerber' ) . '' : __( 'active', 'wp-cerber' ); echo ''; } $s = ''; $scan = cerber_get_scan(); if ( ! $scan || ( WEEK_IN_SECONDS < ( time() - $scan['finished'] ) ) ) { $s = 'style="color: red;"'; } if ( $scan ) { $lms = $scan['mode_h'] . ' ' . cerber_auto_date( $scan['started'] ); } else { $lms = __( 'Never', 'wp-cerber' ); } echo ''; $link = cerber_admin_link( 'scan_schedule' ); $quick = ( ! $lab || ! $q = absint( crb_get_settings( 'scan_aquick' ) ) ) ? __( 'Disabled', 'wp-cerber' ) : cerber_get_qs( $q ); echo ''; $f = ( ! $lab || ! crb_get_settings( 'scan_afull-enabled' ) ) ? __( 'Disabled', 'wp-cerber' ) : crb_get_settings( 'scan_afull' ); echo ''; /* $dev = crb_get_settings('pbdevice'); if (!$dev || $dev == 'N') echo ''; */ echo '
'.__('Lockouts at the moment','wp-cerber').''.$lockouts.'
'.__('Last lockout','wp-cerber').''.$last.'
' . __( 'Logged in users', 'wp-cerber' ) . '' . $s_count . ' ' . _n( 'user', 'users', $s_count, 'wp-cerber' ) . '
'.__('White IP Access List','wp-cerber').''.$w_count.' '._n('entry','entries',$w_count,'wp-cerber').'
'.__('Black IP Access List','wp-cerber').''.$b_count.' '._n('entry','entries',$b_count,'wp-cerber').'
'.__('Citadel mode','wp-cerber').''.$citadel.'
'.__('Traffic Inspector','wp-cerber').''.$status.'
Cloud Protection' . $status . '
' . _x( 'Last malware scan', 'Example: Last malware scan: 23 Jan 2018', 'wp-cerber' ) . '' . $lms . '
' . __( 'Quick Scan', 'wp-cerber' ) . '' . $quick . '
' . __( 'Full Scan', 'wp-cerber' ) . '' . $f . '
'.__('Push notifications','wp-cerber').'not configured
'; echo ''; if ( cerber_check_for_newer() ) { echo '
' . __( 'A new version is available', 'wp-cerber' ) . '
'; } } /* Show Help tab screen */ function cerber_show_help() { switch ( crb_admin_get_page()){ case 'cerber-integrity': cerber_show_scan_help(); break; case 'cerber-nexus': cerber_show_nexus_help(); break; case 'cerber-recaptcha': cerber_show_anti_help(); break; default: cerber_show_general_help(); } } function cerber_show_nexus_help() { global $crb_assets_url; ?>

How remote management works

The technology enables you to manage the WP Cerber plugin, monitor activity, and upgrade plugins on multiple WordPress powered websites from a main WordPress website which is called a master website.

To activate this technology, you need to enable a master mode on the main website and a slave mode on each website you want to connect to the master and manage remotely.

Read more: Manage multiple WP Cerber instances from one dashboard

A safety note

All access tokens are stored in the databases of the master and slave websites in unencrypted form (plaintext). Store a backup copy of all websites in a safe and trusted place.

Troubleshooting

If you’re unable to get it working, that may be caused by a number of reasons. Enable the diagnostic log on the master and on the slave to obtain more information. You can view the log on the Tools admin page. Here is a list of the most common causes of issues on the slave side.

  • A security plugin on the slave website is interfering with the WP Cerber plugin
  • A security directive in the .htaccess file on the slave website is blocking incoming requests as suspicious
  • A firewall or a proxy service (like Cloudflare) is blocking (filtering out) incoming requests to the slave website
  • The IP address of the master is locked out or in the Black Access List on the slave website
  • The slave mode on the remote website has been re-enabled making the security token saved on the master invalid
  • The IP address of the master website does not match the one set in the slave settings on the remote website

Getting started on the master

To configure the main, master website go to the Cerber.Hub admin page and enable master mode. Once you’ve done this you can add slave websites by using security tokens generated on slaves.

Adding slave websites

To add a slave website to the master, you need to enable the slave mode on the website. Go to the Cerber.Hub admin page and enable the slave mode. During the activation of the slave mode, a unique security access token is generated and saved into the database of the slave. Keep the token secret.

Go to the master website and click the “Add” button on the “My Websites” admin page. Copy the token and paste it in the “Add a salve website” popup window.

Manage websites remotely

Once you’ve added all slave websites on the master you can easily switch between them with a single click in a top navigation menu on the admin bar or by clicking the name of a slave on the “My Websites” master page. Once you’ve switched to a slave website use the plugin menu and admin links the way like you do this normally. To switch back to the master website, click a X icon on the admin bar.

Note: when you’re managing remote website, the color of the admin bar is blue and the left admin menu on the master is dimmed.

Using the malware scanner

To start scanning, click either the Start Quick Scan button or the Start Full Scan button. Do not close the browser window while the scan is in progress. You may just open a new browser tab to do something else on the website. Once the scan is finished you can close the window, the results are stored in the DB until the next scan.

Depending on server performance and the number of files, the Quick scan may take about 3-5 minutes and the Full scan can take about ten minutes or less.

During the scan, the plugin verifies plugins, themes, and WordPress by trying to retrieve checksum data from wordpress.org. If the integrity data is not available, you can upload an appropriate source ZIP archive for a plugin or a theme. The plugin will use it to detect changes in files. You need to do it once, after the first scan.

Read more: Cerber Security Scanner Settings

Interpreting scan results

The scanner shows you a list of issues and possible actions you can take. If the integrity of an object has been verified, you see a green mark Verified. If you see the “Integrity data not found” message, you need to upload a reference ZIP archive by clicking “Resolve issue”. For all other issues, click on an appropriate issue link. To view the content of a file, click on its name.

Troubleshooting

If the scanner window stops responding or updating, it usually means the process of scanning on the server is hung. This might happen due to a number of reasons but typically this happens due to a misconfigured server or it’s caused by some hosting limitations. Do the following:

  • Open the browser console (use F12 key on PC or Cmd + Option + J on Mac) and check it for CERBER ERROR messages
  • Try to disable scanning the session directory or the temp directory (or both) in the scanner settings
  • Enable diagnostic logging in the scanner settings and check the log after scanning

Note: The scanner requires the CURL library to be enabled for PHP scripts. Usually, it's enabled by default.

Read more: Malware Scanner & Integrity Checker

What's the Quick Scan?

During the Quick Scan, the scanner verifies the integrity and inspects the code of all files with executable extensions only.

What's the Full Scan?

During the Full Scan, the scanner verifies the integrity and inspects the content of all files on the website. All media files are scanned for malicious payload.

Read more: What Cerber Security Scanner scans and detects

Configuring scheduled scans

In the Automated recurring scan schedule section you set up your schedule. Select the desired frequency of the Quick Scan and specify the time of the Full Scan. By default, all automated recurring scans are turned off.

The Scan results reporting section is about reporting. Here you can easily and flexibly configure conditions for generating and sending reports.

The email report will only include issues that match conditions in the Report an issue if any of the following is true filter. So this setting works as a filter for issues you want to get in a email report. The report will only be sent if there are issues to report and the following condition is true.

The second condition is configured with Send email report. The report will be sent if a selected condition is true. The last option is the most restrictive.

Read more: Automated recurring scans and email reporting

Automatic cleanup of malware

The plugin can automatically delete malicious and suspicious files. Automatic removal policies are enforced at the end of every scheduled scan based on its results. The list of files to be deleted depends on the scanner settings. By default automatic removal is disabled. It's advised to enable it at least for unattended files and files in the media uploads folder for files with the High severity risk. The plugin deletes only files that have malicious or suspicious code payload. All detected malicious and suspicious files are moved to the quarantine.

Read more: Automatic cleanup of malware and suspicious files

Deleting files

Usually, you can delete any suspicious or malicious file if it has a checkbox in its row in the leftmost cell. Before deleting a file, click the issue link in its row to see an explanation. When you delete a file WP Cerber moves it to a quarantine folder.

Restoring deleted files

If you delete an important file by chance, you can restore the file from the quarantine. To restore one or more files from within the WordPress dashboard, click the Quarantine tab. Find the filename in the File column and click Restore in the Action column. The file will be restored to its original location.

To restore a file manually, you need to use a file manager in your hosting control panel. All deleted files are stored in a special quarantine folder. The location of the folder is shown on the Tools / Diagnostic admin page. The original name and location of a deleted file are saved in a .restore file. It’s a text file. Open it in a browser or a file viewer, find the filename you need to restore in a list of deleted files and copy the file back to its location by using the original name and location of the file.

Setting up anti-spam protection

The Cerber anti-spam and bot detection engine is capable to protect virtually any form on a website. It’s a great alternative to reCAPTCHA. Tested with Caldera Forms, Gravity Forms, Contact Form 7, Ninja Forms, Formidable Forms, Fast Secure Contact Form, Contact Form by WPForms and WooCommerce forms.

How to stop spam user registrations on your WordPress

How to stop spam form submissions on your WordPress

Configuring exceptions for the anti-spam engine

Usually, you need to specify an exception if you use a plugin or some technology that communicates with your website by submitting forms or sending POST requests programmatically. In this case, Cerber can block these legitimate requests because it recognizes them as generated by bots. This may lead to multiple false positives which you can see on the Activity tab. These entries are marked as Spam form submission denied.

Configuring exceptions for the anti-spam engine

How to set up reCAPTCHA

Before you can start using reCAPTCHA on the website, you have to obtain a Site key and a Secret key on the Google website. To get the keys you have to have Google account. Register your website and get both keys here: https://www.google.com/recaptcha/admin Note: If you are going to use an invisible version, you must get and use Site key and a Secret key for the invisible version only.

How to set up reCAPTCHA in details

Why does reCAPTCHA not protect WordPress against bots and brute-force attacks?

Troubleshooting

Configuring exceptions for the antispam engine

I’m getting "Probing for vulnerable PHP code"

Some legitimate HTTP requests are being blocked

PHP Warning: Cannot modify header information – headers already sent in

Traffic Inspector

Traffic Inspector is a set of specialized request inspection algorithms that acts as an additional protection layer (firewall) for your WordPress

Traffic Inspector in a nutshell

What's new in this version of the plugin?

Check out release notes

Online Documentation

All articles on wpcerber.com

How to protect WordPress effectively: a must-do list

What is IP address of your computer?

To find out your current IP address go to this page: What is my IP. If you see a different IP address on the Activity tab for your login or logout events, try to enable .

Solving problem with incorrect IP address detection

Setting up antispam protection

The Cerber antispam and bot detection engine is capable to protect virtually any form on a website. It’s a great alternative to reCAPTCHA.

How to stop spam user registrations on your WordPress

Antispam protection for contact forms

Configuring exceptions for the antispam engine

Mobile and browser notifications with Pushbullet

WP Cerber allows you to easily enable desktop and mobile notifications and get notifications instantly and for free. In a desktop browser, you will get popup messages even if you logged out of your WordPress. Before you start receiving notifications you need to install a free Pushbullet mobile application on your mobile device or free browser extension available for Chrome, Firefox and Opera.

A three steps instruction how to set up push notifications

How to get alerts for specific activity on your website

WordPress security explained

Why does reCAPTCHA not protect WordPress against bots and brute-force attacks?

Why you need to use Custom login URL for your WordPress

Why it's important to restrict access to the WP REST API

Brute-force, DoS, and DDoS attacks - what's the difference?

What is Drill down IP?

To get extra information like country, company, network info, abuse contact etc. for a specific IP address, the plugin makes requests to a limited set of external WHOIS servers which are maintained by appropriate Registry. All Registry are accredited by ICANN, so there are no reasons for security concerns. Retrieved information isn't storing in the database, but it is caching for up to 24 hours to avoid excessive requests and get faster response.

Read more in the Security Blog

What is Cerber Lab?

Cerber Laboratory is a forensic team at Cerber Tech Inc. The team studies and analyzes patterns of hacker and botnet attacks, malware, vulnerabilities in major plugins and how they are exploitable on WordPress powered websites.

Know more

Do you have an idea for a cool new feature that you would love to see in WP Cerber?

Feel free to submit your ideas here: New Feature Request.

Are you ready to translate this plugin into your language?

I would appreciate that! Please, notify me

Check out other plugins from the trusted author

Plugin for inspecting code of plugins on your site: Plugin Inspector

The Plugin Inspector plugin is an easy way to check plugins installed on your WordPress and make sure that plugins does not use deprecated WordPress functions and some unsafe functions like eval, base64_decode, system, exec etc. Some of those functions may be used to load malicious code (malware) from the external source directly to the site or WordPress database.

Plugin Inspector allows you to view all the deprecated functions complete with path, line number, deprecation function name, and the new recommended function to use. The checks are run through a simple admin page and all results are displayed at once. This is very handy for plugin developers or anybody who want to know more about installed plugins.

Plugin to quick translate site: Google Translate Widget

Google Translate Widget expands your global reach quickly and easily. Google Translate is a free multilingual machine translation service provided by Google to translate websites. And now you can allow visitors around of the world to get your site in their native language. Just put widget on the sidebar with one click.

Submit a support ticket on our Help Desk: https://my.wpcerber.com

'; } else { $support = '

Support for the free version is provided on the WordPress forum only, though, please note, that it is free support hence it is not always possible to answer all questions on a timely manner, although we do try.

If you need professional and priority support 24/7/365, please buy a PRO license

'; } ?>

How to configure the plugin

To get the most out of Cerber Security, you need to configure the plugin properly

Please read this first: Getting Started Guide

Do you have a question or need help?

Get answer on the support forum

Search plugin documentation on wpcerber.com

'; $kpi_list = cerber_calculate_kpi( 1 ); $kpi_show = ''; foreach ( $kpi_list as $kpi ) { $kpi_show .= '' . $kpi[1] . '' . $kpi[0] . ''; } $kpi_show = '' . $kpi_show . '
'; // TODO: add link "send daily report to my email" echo '
' . $kpi_show . '

' . __( 'in the last 24 hours', 'wp-cerber' ) . '

'; $total = cerber_db_get_var( 'SELECT count(ip) FROM ' . CERBER_LOG_TABLE ); //if ($total > $num) $l1 = 'Last ' . $num . ' suspect events are displayed'; $nav_links = ( $total ) ? crb_admin_quick_nav( 'dashboard' ) : ''; echo '

' . __( 'Activity', 'wp-cerber' ) . '

' . $nav_links . '
'; cerber_show_activity( array( 'filter_activity' => crb_get_activity_set( 'dashboard' ), 'per_page' => 10, 'no_navi' => true, 'no_export' => true, 'no_details' => true, 'date' => 'ago' ) ); $view = ''; if ( cerber_blocked_num() ) { $view = '' . __( 'View all', 'wp-cerber' ) . ''; } echo '

' . __( 'Recently locked out IP addresses', 'wp-cerber' ) . '

' . $view . '
'; cerber_show_lockouts( array( 'per_page' => 10, 'no_navi' => true ) ); } /* Admin aside bar */ function cerber_show_aside( $page ) { global $crb_assets_url; if ( in_array( $page, array( 'nexus_sites', 'activity', 'lockouts', 'traffic' ) ) ) { return; } $aside = array(); if ( in_array( $page, array( 'main' ) ) ) { $aside[] = '

' . __( 'Confused about some settings?', 'wp-cerber' ) . '

' . __( 'You can easily load default recommended settings using button below', 'wp-cerber' ) . '

* ' . __( "doesn't affect Custom login URL and Access Lists", 'wp-cerber' ) . '

' . __( 'Getting Started Guide', 'wp-cerber' ) . '

'; } /* $aside[] = '

Be in touch with developer

Receive updates and helpful ideas to protect your website, blog, or business online.

  Subscribe to Cerber\'s newsletter
  Follow Cerber on Twitter
  Follow Cerber on Facebook

';*/ if ( ! lab_lab() ) { $aside[] = ' Follow Cerber on Twitter'; // Subscribe to Cerber\'s newsletter // Follow Cerber on Facebook //'; // 22.01.2017 /* * $aside[] = '

UPGRADE TO PROFESSIONAL VERSION
'; */ $aside[] = ''; } $aside[] = '

Documentation & How To

Managing multiple WP Cerber instances from one dashboard

Stay in compliance with GDPR

Two-Factor Authentication for WordPress

How to protect WordPress effectively: a must-do list

Automatic cleanup of malware and suspicious files

Automated recurring scans and email reporting

Instant mobile and browser notifications

WordPress notifications made easy

How to limit access to the WP REST API

'; if ( ! lab_lab() ) { $a = cerber_get_set( '_activated' ); if ( ! $a || ( ! empty( $a['time'] ) && $a['time'] < ( time() - WEEK_IN_SECONDS ) ) ) { $aside[] = ''; } } echo '
'.implode(' ',$aside).'
'; } /* Displaying notices in the dashboard */ add_action( 'load-plugins.php', function () { add_action( 'admin_notices', 'cerber_show_admin_notice', 999 ); add_action( 'network_admin_notices', 'cerber_show_admin_notice', 999 ); } ); function cerber_show_admin_notice(){ global $cerber_shown; $cerber_shown = false; if (cerber_is_citadel() && current_user_can('manage_options')) { echo '

'. __('Attention! Citadel mode is now active. Nobody is able to log in.','wp-cerber'). '   '.__('Deactivate','wp-cerber').''. ' | ' . __('View Activity','wp-cerber') . '' . '

'; } if ( ! nexus_is_valid_request() && ! cerber_is_admin_page( true ) ) { return; } //if ($notices = get_site_option('cerber_admin_notice')) // echo '

'.$notices.'

'; // class="updated" - green, class="update-nag" - yellow and above the page title, //if ($notices = get_site_option('cerber_admin_message')) // echo '

'.$notices.'

'; // class="updated" - green, class="update-nag" - yellow and above the page title, $all = array(); if ( ! empty( $_GET['settings-updated'] ) ) { $all[] = array( __( 'Settings saved', 'wp-cerber' ), 'updated' ); } if ( $notice = cerber_get_set( 'admin_notice' ) ) { if ( is_array( $notice ) ) { $notice = '

' . implode( '

', $notice ) . '

'; } $all[] = array( $notice, 'error' ); // red } if ( $notice = cerber_get_set( 'admin_message' ) ) { if ( is_array( $notice ) ) { $notice = '

' . implode( '

', $notice ) . '

'; } $all[] = array( $notice, 'updated' ); // green } if ( $all ) { $cerber_shown = true; foreach ( $all as $notice ) { echo '

' . $notice[0] . '

'; } } crb_clear_admin_msg(); if ( $cerber_shown || ! cerber_is_admin_page() ) { return; } if ( $notice = get_site_option( 'cerber_admin_info' ) ) { // need to be dismissed manually $cerber_shown = true; echo '

' . $notice . '

'; return; } lab_opt_in(); } /** * Generates a link for subscribing on a currently displaying Activity page * * @return string Link for using in the Dashboard, HTML */ function crb_admin_alert_link() { $args = array_values( cerber_get_alert_params() ); // All activities, without any filter is not allowed $empty = array_filter( $args ); if ( empty( $empty ) ) { return ''; } $subs = cerber_get_site_option( '_cerber_subs' ); // Limit to the number of subscriptions if ( $subs && count( $subs ) > 50 ) { return ''; } $mode = 'on'; if ( $subs ) { $hash = sha1( json_encode( $args ) ); if ( recursive_search_key( $subs, $hash ) ) { $mode = 'off'; } } $link = cerber_admin_link_add( array( 'cerber_admin_do' => 'subscribe', 'mode' => $mode ), true ); if ( $mode == 'on' ) { $text = __( 'Create Alert', 'wp-cerber' ); $icon = 'crb-icon-bxs-bell'; } else { $text = __( 'Delete Alert', 'wp-cerber' ); $icon = 'crb-icon-bxs-bell-off'; } //return ' '.$text.''; return ' ' . $text . ''; } /** * Managing the list of subscriptions * * @param string $mode Add or delete a subscription * @param string $hash If specified, subscription with given hash will be removed */ function crb_admin_alerts_do( $mode = 'on', $hash = null ) { if ( $hash ) { $mode = 'off'; } else { $args = array_values( cerber_get_alert_params() ); $hash = sha1( json_encode( $args ) ); } $subs = get_site_option( '_cerber_subs' ); if ( ! $subs ) { $subs = array(); } if ( $mode == 'on' ) { $subs[ $hash ] = $args; $msg = __( "The alert has been created", 'wp-cerber' ); } else { unset( $subs[ $hash ] ); $msg = __( "The alert has been deleted", 'wp-cerber' ); } if ( update_site_option( '_cerber_subs', $subs ) ) { cerber_admin_message( $msg ); } } // Unsubscribe with hash with no admin nonce add_action( 'admin_init', function () { if ( $hash = cerber_get_get( 'unsubscribeme', '[a-z\d]+' ) ) { crb_admin_alerts_do( 'off', $hash ); wp_safe_redirect( remove_query_arg( 'unsubscribeme' ) ); exit; } } ); /* Pagination */ function cerber_page_navi( $total, $per_page ) { $max_links = 10; if ( ! $per_page ) { $per_page = 25; } $page = cerber_get_pn(); $base_url = esc_url( remove_query_arg( 'pagen', add_query_arg( crb_get_query_params(), cerber_admin_link() ) ) ); $last_page = ceil( $total / $per_page ); $ret = ''; if ( $last_page > 1 ) { $start = 1 + $max_links * intval( ( $page - 1 ) / $max_links ); $end = $start + $max_links - 1; if ( $end > $last_page ) { $end = $last_page; } if ( $start > $max_links ) { $links[] = '«'; } for ( $i = $start; $i <= $end; $i ++ ) { if ( $page != $i ) { $links[] = '' . $i . ''; } else { $links[] = '' . $i . ' '; } } if ( $end < $last_page ) { $links[] = '»'; // ➝ } $ret = '
' . $total . ' ' . _n( 'entry', 'entries', $total, 'wp-cerber' ) . '
'; } return $ret; } function cerber_get_pn() { $q = crb_admin_parse_query( array( 'pagen' ) ); return ( ! $q->pagen ) ? 1 : absint( $q->pagen ); } /* Plugins screen links */ add_filter('plugin_action_links','cerber_action_links',10,4); function cerber_action_links($actions, $plugin_file, $plugin_data, $context){ if($plugin_file == CERBER_PLUGIN_ID){ $link[] = '' . __('Dashboard','wp-cerber') . ''; $link[] = '' . __('Main settings','wp-cerber') . ''; $actions = array_merge ($link,$actions); } return $actions; } /* function add_some_pointers() { ?> 'cerber-integrity' ) ) ) { wp_enqueue_script( 'cerber_scan', $crb_assets_url . 'scanner.js', array( 'jquery' ), CERBER_VER, true ); } } wp_register_style( 'crb_icons_css', $crb_assets_url . 'icons/style.css', null, CERBER_VER ); wp_enqueue_style( 'crb_icons_css' ); wp_register_style( 'cerber_css', $crb_assets_url . 'admin.css', null, CERBER_VER ); wp_enqueue_style( 'cerber_css' ); } /* * JS & CSS for admin head * */ add_action('admin_head', 'cerber_admin_head' ); add_action('customize_controls_print_scripts', 'cerber_admin_head' ); // @since 5.8.1 function cerber_admin_head() { global $crb_assets_url, $crb_ajax_loader; //$crb_ajax_loader = $crb_assets_url . 'ajax-loader.gif'; $crb_ajax_nonce = wp_create_nonce( 'crb-ajax-admin' ); $crb_lab_available = ( lab_lab() ) ? 'true' : 'false'; ?> $uid ) ) . '" class="page-title-action">' . __( 'View Activity', 'wp-cerber' ) . ''; ?> array( 'scan_schedule', 'scan_policy' ) ) ) ) : ?> '; } add_filter( 'admin_footer_text', function ( $text ) { if ( ! cerber_is_admin_page() ) { return $text; } return 'If you like WP Cerber, please give it a ★ ★ ★ ★ ★ review. Thanks!'; }, PHP_INT_MAX ); add_filter( 'update_footer', function ( $text ) { if ( ! cerber_is_admin_page() ) { return $text; } if ( lab_lab() ) { $pr = 'PRO'; $support = 'Get Support'; } else { $pr = ''; $support = 'Support Forum'; } if ( 1 == cerber_get_mode() ) { $mode = 'in the Standard mode'; } else { $mode = 'in the Legacy mode'; } return 'WP Cerber Security ' . $pr . ' ' . CERBER_VER . '. ' . $mode . ' | ' . $support; }, PHP_INT_MAX ); /* * Add per admin screen settings */ function crb_admin_screen_options() { if ( ! $id = crb_get_configurable_screen() ) { return; } $args = array( //'label' => __( 'Number of items per page:' ), 'default' => 25, 'option' => 'cerber_screen_' . $id, ); add_screen_option( 'per_page', $args ); } /* * Allows to save screen settings to the user meta */ add_filter( 'set-screen-option', function ( $status, $option, $value ) { if ( $id = crb_get_configurable_screen() ) { if ( 'cerber_screen_' . $id == $option ) { return $value; } } return $status; }, 10, 3 ); function crb_get_configurable_screen() { if ( ! $id = crb_admin_get_tab() ) { $id = crb_admin_get_page(); } if ( $id == 'cerber-traffic' ) { $id = 'traffic'; } if ( ( $id == 'cerber-nexus' ) && nexus_is_master() ) { return 'nexus_sites'; } $ids = array( 'lockouts', 'activity', 'traffic', 'scan_quarantine', 'scan_ignore', 'nexus_sites' ); if ( ! in_array( $id, $ids ) ) { return false; } return $id; } /* * Retrieve settings for the current screen * */ function crb_admin_get_per_page() { if ( is_multisite() ) { return 50; // temporary workaround } if ( nexus_is_valid_request() ) { $per_page = nexus_request_data()->screen['per_page']; } elseif ( function_exists( 'get_current_screen' ) ) { set_current_screen(); $screen = get_current_screen(); if ( $screen_option = $screen->get_option( 'per_page', 'option' ) ) { $per_page = absint( get_user_meta( get_current_user_id(), $screen_option, true ) ); if ( empty ( $per_page ) ) { $per_page = absint( $screen->get_option( 'per_page', 'default' ) ); } } } if ( empty ( $per_page ) ) { $per_page = 25; } return absint( $per_page ); } /** * @param array $tabs_config array of tabs: title, desc, contents and optional JS callback * @param string $submit Text for the submit button * @param array $hidden Hidden form fiedls * */ function crb_admin_show_vtabs( $tabs_config, $submit = '', $hidden = array(), $form_id = '' ) { $tablinks = ''; $tabs = ''; $b_class = 'active'; $t_style = ''; $callbacks = array(); foreach ( $tabs_config as $tab_id => $tab ) { $tab_id = str_replace( '-', '_', $tab_id ); $tablinks .= ''; $tabs .= '
' . $tab['content'] . '
'; if ( $b_class ) { $b_class = ''; $t_style = 'style= "display: none;"'; } $callbacks[] = '' . $tab_id . ':"' . crb_array_get( $tab, 'callback', '' ) . '"'; } $js_code = '/* VTabs JS code */'; $js_code .= 'var vtabs_callbacks = {' . implode( ',', $callbacks ) . '};' . "\n"; reset( $tabs_config ); $js_code .= 'var vtabs_first_id = "' . key( $tabs_config ) . '";' . "\n"; echo '
'; if ( ! $submit ) { $submit = __( 'Save Changes' ); } echo '
' . $tablinks . '
' . $tabs . '
' . crb_admin_submit_button( $submit ) . '
'; cerber_nonce_field( 'control', true ); if ( $hidden ) { foreach ( $hidden as $name => $val ) { echo ''; } } echo '
'; ?> $rule ) { list( $desc, $content ) = crb_admin_geo_selector( $rule_id, $rule ); if ( isset( $rule['multi_set'] ) ) { $names = array( '---first' => $rule['multi_top'] . ' — ' . $desc ); foreach ( $rule['multi_set'] as $item_id => $item_title ) { $id = $rule_id . '_' . $item_id; list( $d, $c ) = crb_admin_geo_selector( $id, $rule, 'crb-display-none' ); $content .= $c; if ( cerber_get_geo_rules( $id ) ) { $desc = __( 'Role-based rules are configured', 'wp-cerber' ); $names[ $item_id ] = $item_title . ' — ' . $d; } else { $names[ $item_id ] = $item_title; } } $content = '

' . cerber_select( 'sw_' . $rule_id, $names, null, 'crb-geo-switcher', null, null, null, array( 'rule-id' => $rule_id ) ) . '

' . $content; } $tabs_config[ $rule_id ] = array( 'title' => $rule['name'], 'desc' => $desc, 'content' => '
' . $content . '
', 'callback' => 'geo_rules_activator', ); } ?> 'update_geo_rules' ), 'crb-geo-rules' ); } function crb_admin_geo_selector( $rule_id, $rule, $class = '' ) { $config = cerber_get_geo_rules( $rule_id ); $selector = crb_geo_country_selector( $config, $rule_id, $rule ); $opt = crb_get_settings(); if ( ! empty( $config['list'] ) ) { $num = count( $config['list'] ); if ( $config['type'] == 'W' ) { $info = sprintf( _n( 'Permitted for one country', 'Permitted for %d countries', $num, 'wp-cerber' ), $num ); } else { $info = sprintf( _n( 'Not permitted for one country', 'Not permitted for %d countries', $num, 'wp-cerber' ), $num ); } if ( $num == 1 ) { $info .= ' (' . current( $config['list'] ) . ')'; //$info .= ' (' . cerber_get_flag_html($c) . $c . ')'; } } else { $info = __( 'No rule', 'wp-cerber' ); $info = __( 'Any country is permitted', 'wp-cerber' ); } $note = ''; switch ( $rule_id ) { case 'geo_register': if ( ! get_option( 'users_can_register' ) ) { $note = 'Registration is disabled in the General Settings'; } break; case 'geo_restapi': if ( $opt['norest'] ) { $note = 'REST API is disabled in the Hardening settings of the plugin'; } break; case 'geo_xmlrpc': if ( $opt['xmlrpc'] ) { $note = 'XML-RPC is disabled in the Hardening settings of the plugin'; } break; } if ( $note ) { $note = '

Note: ' . $note . '

'; } return array( $info, $note . '
' . $selector . '
' ); } /** * Generates GEO rule selector * * @param array $config Rule configuration * @param string $rule_id * @param array $rule * * @return string HTML code of form */ function crb_geo_country_selector( $config = array(), $rule_id = '', $rule = array() ) { $ret = '

' . __( 'Click on a country name to add it to the list of selected countries', 'wp-cerber' ) . '

'; return $ret; } /** * A list of available GEO rules * * @return array */ function cerber_geo_rule_set() { $set = wp_roles()->role_names; $rules = array( 'geo_login' => array( 'name' => __( 'Log in to the website', 'wp-cerber' ), 'multi_set' => $set, 'multi_top' => __( 'All Users' ) ), 'geo_register' => array( 'name' => __( 'Register on the website', 'wp-cerber' ) ), 'geo_submit' => array( 'name' => __( 'Submit forms', 'wp-cerber' ) ), 'geo_comment' => array( 'name' => __( 'Post comments', 'wp-cerber' ) ), 'geo_xmlrpc' => array( 'name' => __( 'Use XML-RPC', 'wp-cerber' ) ), 'geo_restapi' => array( 'name' => __( 'Use REST API', 'wp-cerber' ) ), ); return $rules; } function crb_admin_save_geo_rules( $post_fields = array() ) { global $cerber_country_names, $check, $admin_country; if ( ! lab_lab() ) { return; } $check = array_keys( $cerber_country_names ); // Prevent admin country from being blocked if ( nexus_is_valid_request() ) { $admin_country = null; } else { $admin_country = lab_get_country( cerber_get_remote_ip(), false ); } $geo = array(); foreach ( cerber_geo_rule_set() as $rule_id => $rule ) { if ( $data = crb_admin_process_geo( $post_fields, $rule_id ) ) { $geo[ $rule_id ] = $data; } if ( isset( $rule['multi_set'] ) ) { foreach ( $rule['multi_set'] as $item_id => $item_title ) { $id = $rule_id . '_' . $item_id; if ( $data = crb_admin_process_geo( $post_fields, $id ) ) { $geo[ $id ] = $data; } } } } if ( update_site_option( 'geo_rule_set', $geo ) ) { cerber_admin_message( __( 'Security rules have been updated', 'wp-cerber' ) ); } } function crb_admin_process_geo( $post, $rule_id ) { global $check, $admin_country; if ( empty( $post[ 'crb-' . $rule_id . '-list' ] ) || empty( $post[ 'crb-' . $rule_id . '-type' ] ) ) { return false; } $list = array_intersect( $post[ 'crb-' . $rule_id . '-list' ], $check ); if ( $post[ 'crb-' . $rule_id . '-type' ] == 'B' ) { $type = 'B'; if ( $admin_country && ( ( $key = array_search( $admin_country, $list ) ) !== false ) ) { unset( $list[ $key ] ); } } else { $type = 'W'; if ( $admin_country && ( ( $key = array_search( $admin_country, $list ) ) === false ) ) { array_push( $list, $admin_country ); } } return array( 'list' => $list, 'type' => $type ); } /** * Generates HTML for showing country in UI * * @param null $code * @param null $ip * * @return string */ function crb_country_html($code = null, $ip = null){ global $crb_ajax_loader; if (!lab_lab()){ return ''; } if ( ! $code ) { if ( $ip ) { $code = lab_get_country( $ip ); } else { return ''; } } if ( $code ) { //$country = cerber_get_flag_html( $code ) . ''.cerber_country_name( $code ).''; $ret = cerber_get_flag_html( $code, cerber_country_name( $code ) ); } else { $ip_id = cerber_get_id_ip($ip); $ret = '' . "\n"; } return $ret; } // Traffic ===================================================================================== function cerber_export_traffic( $params = array() ) { crb_raise_limits( 512 ); $args = array( 'per_page' => 0, 'columns' => array( 'ip', 'stamp', 'uri', 'session_id', 'user_id', 'processing', 'request_method', 'http_code', 'wp_type', 'blog_id' ) ); if ( $params ) { $args = array_merge( $params, $args ); } list( $query, $found ) = cerber_traffic_query( $args ); // We split into several requests to avoid PHP and MySQL memory limitations if ( defined( 'CERBER_EXPORT_CHUNK' ) && is_numeric( CERBER_EXPORT_CHUNK ) ) { $per_chunk = CERBER_EXPORT_CHUNK; } else { $per_chunk = 1000; // Rows per SQL request, we assume that this number is not too small and not too big } if ( ! $result = cerber_db_query( $query . ' LIMIT ' . $per_chunk ) ) { wp_die( 'Nothing to export' ); } $total = cerber_db_get_var( $found ); $info = array(); $heading = array( __( 'IP address', 'wp-cerber' ), __( 'Date', 'wp-cerber' ), 'Method', 'URI', 'HTTP Code', 'Request ID', __( 'User ID', 'wp-cerber' ), __( 'Page generation time', 'wp-cerber' ), 'Blog ID', 'Type', 'Unix Timestamp', ); cerber_send_csv_header( 'wp-cerber-http-requests', $total, $heading, $info ); //$labels = cerber_get_labels( 'activity' ); //$status = cerber_get_labels( 'status' ); $i = 0; do { while ( $row = mysqli_fetch_assoc( $result ) ) { $values = array(); /* $values[] = $row->ip; $values[] = cerber_date( $row->stamp ); $values[] = $row->request_method; $values[] = $row->uri; $values[] = $row->http_code; $values[] = $row->session_id; $values[] = $row->user_id; $values[] = $row->processing; $values[] = $row->blog_id; $values[] = $row->wp_type; $values[] = $row->stamp;*/ $values[] = $row['ip']; $values[] = cerber_date( $row['stamp'] ); $values[] = $row['request_method']; $values[] = $row['uri']; $values[] = $row['http_code']; $values[] = $row['session_id']; $values[] = $row['user_id']; $values[] = $row['processing']; $values[] = $row['blog_id']; $values[] = $row['wp_type']; $values[] = $row['stamp']; cerber_send_csv_line( $values ); } mysqli_free_result( $result ); $i++; $offset = $per_chunk * $i; } while ( ( $result = cerber_db_query( $query . ' LIMIT ' . $offset . ', ' . $per_chunk ) ) && $result->num_rows ); exit; } /* * Display traffic in the WP Dashboard * @since 6.0 * */ function cerber_show_traffic( $args = array(), $echo = true ) { global $wpdb, $crb_ajax_loader, $wp_cerber_remote; $labels = cerber_get_labels( 'activity' ); $status_labels = cerber_get_labels( 'status' ) + cerber_get_reason(); $base_url = cerber_admin_link( 'traffic' ); //$activity_url = cerber_admin_link( 'activity' ); $export_button = ''; $ret = ''; $total = 0; if ( ! $wp_cerber_remote ) { list( $query, $found, $per_page, $filter_act, $filter_ip, $prc, $user_id ) = cerber_traffic_query( $args ); $rows = cerber_db_get_results( $query, MYSQL_FETCH_OBJECT_K ); $total = cerber_db_get_var( $found ); if ( $rows ) { $acf = ( $filter_act ) ? ' log.activity IN (' . $filter_act . ')' : ' log.activity NOT IN (10,11)'; //$events = cerber_db_get_results( 'SELECT log.session_id,log.* FROM ' . CERBER_LOG_TABLE . ' log WHERE log.session_id IN ("' . implode( '", "', array_keys( $rows ) ) . '" )', MYSQL_FETCH_OBJECT_K ); $events = cerber_db_get_results( 'SELECT log.session_id,log.* FROM ' . CERBER_LOG_TABLE . ' log WHERE log.session_id IN ("' . implode( '", "', array_keys( $rows ) ) . '" ) AND ' . $acf, MYSQL_FETCH_OBJECT_K ); $roles = wp_roles()->roles; $users = array(); $acl = array(); $block = array(); $wp_objects = array(); foreach ( $rows as $row ) { if ( $row->user_id && ! isset( $users[ $row->user_id ] ) ) { if ( $u = get_userdata( $row->user_id ) ) { $n = $u->display_name; $r = ''; if ( ! is_multisite() && $u->roles ) { $r = array(); foreach ( $u->roles as $role ) { $r[] = $roles[ $role ]['name']; } $r = '' . implode( ', ', $r ) . ''; } } else { $n = __( 'Unknown', 'wp-cerber' ) . ' (' . $row->user_id . ')'; $r = ''; } $users[ $row->user_id ]['name'] = $n; $users[ $row->user_id ]['roles'] = $r; } if ( ! isset( $acl[ $row->ip ] ) ) { $acl[ $row->ip ] = cerber_acl_check( $row->ip ); } if ( ! isset( $block[ $row->ip ] ) ) { $block[ $row->ip ] = cerber_block_check( $row->ip ); } // TODO: make it compatible with multisite WP if ( $row->wp_type == 601 && $row->wp_id > 0 ) { $title = cerber_db_get_var( 'SELECT post_title FROM ' . $wpdb->posts . ' WHERE ID = ' . absint( $row->wp_id ) ); if ( $title ) { $wp_objects[ $row->wp_id ] = apply_filters( 'the_title', $title, $row->wp_id ); } } } } } $info = ''; if ($filter_ip) { $info .= cerber_ip_extra_view( $filter_ip, 'traffic' ); } if ($user_id){ list( $sname, $tmp ) = cerber_user_extra_view( $user_id, 'traffic' ); $info .= $tmp; } if ( $rows ) { $tbody = ''; $country = ''; $geo = lab_lab(); foreach ($rows as $row) { // URI $full_uri = urldecode( $row->uri ); $full_uri = htmlentities( $full_uri ); $row_uri = $full_uri; $truncated = false; if ( strlen( $full_uri ) > 220 ) { $truncated = true; $row_uri = substr( $full_uri, 0, 220 ); } $row_uri = str_replace( array( '-', '/', '%', '&', '=', '?', '(', ')', ), array( '-', '/', '%', '&', '=', '?', '(', ')' ), $row_uri ); $full_uri = str_replace( array( '-', '/', '%', '&', '=', '?', '(', ')', ), array( '-', '/', '%', '&', '=', '?', '(', ')' ), $full_uri ); if ( $truncated ) { $row_uri .= ' '; } // User $ip_id = cerber_get_id_ip( $row->ip ); if ( $row->user_id ) { $name = '' . $users[ $row->user_id ]['name'] . '
' . $users[ $row->user_id ]['roles']; } else { $name = ''; } $ip = '' . $row->ip . ''; if ( ! empty( $row->hostname ) ) { $hostname = $row->hostname; } else { $ip_info = cerber_get_ip_info( $row->ip, true ); if ( isset( $ip_info['hostname_html'] ) ) { $hostname = $ip_info['hostname_html']; } else { $hostname = '' . "\n"; } } $tip=''; if ( $acl[ $row->ip ] == 'W' ) { $tip = __( 'White IP Access List', 'wp-cerber' ); } elseif ( $acl[ $row->ip ] == 'B' ) { $tip = __( 'Black IP Access List', 'wp-cerber' ); } if ( $block[ $row->ip ] ) { $color = ' color-blocked '; $tip .= ' ' . __( 'Locked out', 'wp-cerber' ); } else { $color = ''; } if ( ! empty( $args['date'] ) && $args['date'] == 'ago' ) { $date = cerber_ago_time( $row->stamp ); } else { $date = '' . cerber_date( $row->stamp ) . ''; } if ( $geo ) { $country = '

' . crb_country_html( $row->country, $row->ip ) . '

'; } $activity = ''; if ( ! empty( $events[ $row->session_id ] ) ) { $a = $events[ $row->session_id ]; //$activity = '

' . $labels[ $a->activity ] . ''; $activity = '

' . $labels[ $a->activity ] . ''; $ad = explode( '|', $a->details ); if ( ! empty( $ad[0] ) ) { $activity .= ' ' . $status_labels[ $ad[0] ] . ''; } } if ( $row->processing ) { $processing = $row->processing . ' ms'; if ( ( $threshold = crb_get_settings( 'tithreshold' ) ) && $row->processing > $threshold ) { $processing = '' . $processing . ''; } } else { $processing = ''; } $wp_type = '' . cerber_get_wp_type( $row->wp_type ) . ''; $wp_obj = ''; if ( isset( $wp_objects[ $row->wp_id ] ) ) { $wp_obj = '

' . $wp_objects[ $row->wp_id ] . '

'; } $more_details = array(); if ( $truncated ) { $more_details[] = array( 'Full URL', '' . $full_uri . '' ); } $fields = array(); if ( ! empty( $row->request_fields ) ) { $fields = @unserialize( $row->request_fields ); } $details = array(); if ( ! empty( $row->request_details ) ) { $details = @unserialize( $row->request_details ); } if ( ! empty( $details[2] ) ) { $more_details[] = array( 'Referrer', '' . htmlentities( urldecode( $details[2] ) ) . '' ); } if ( ! empty( $details[1] ) ) { $more_details[] = array( 'User Agent', '' . htmlentities( $details[1] ) . '' ); } // POST fields if ( ! empty( $fields[1] ) ) { $more_details[] = array( '', cerber_table_view( 'Form fields', $fields[1] ) ); } // GET fields if ( ! empty( $fields[2] ) ) { $more_details[] = array( '', cerber_table_view( 'GET fields', $fields[2] ) ); } // Files $files = array(); $f = ''; if ( ! empty( $fields[3] ) ) { foreach ( $fields[3] as $field_name => $file ) { if ( is_array( $file['error'] ) ) { $f_err = array_shift( $file['error'] ); } else { $f_err = $file['error']; } if ( $f_err == UPLOAD_ERR_NO_FILE ) { continue; } if ( is_array( $file['name'] ) ) { $f_name = array_shift( $file['name'] ); } else { $f_name = $file['name']; } if ( is_array( $file['size'] ) ) { $f_size = array_shift( $file['size'] ); } else { $f_size = $file['size']; } $files[ $field_name ] = htmlentities( $f_name ) . ', size: ' . absint( $f_size ) . ' bytes'; } if ( ! empty( $files ) ) { $f = 'F'; $more_details[] = array( '', cerber_table_view( 'Files submitted', $files ) ); } } // Additional details if ( ! empty( $details[5] ) ) { $more_details[] = array( 'XML-RPC Data', htmlentities( $details[5] ) ); } if ( ! empty( $details[6] ) ) { $more_details[] = array( '', cerber_table_view( 'Headers', $details[6] ) ); } if ( ! empty( $details[8] ) ) { $more_details[] = array( '', cerber_table_view( 'Cookies', $details[8] ) ); } if ( ! empty( $details[7] ) ) { $more_details[] = array( '', cerber_table_view( '$_SERVER', $details[7] ) ); } $php_err = ''; if ( ! empty( $row->php_errors ) ) { $err_list = @unserialize( $row->php_errors ); if ( $err_list ) { $err = array(); foreach ( $err_list as $e ) { $err[] = array( 'type' => cerber_get_err_type( $e[0] ) . ' (' . $e[0] . ')', 'info' => $e[1], 'file' => $e[2], 'line' => $e[3] ); } $more_details[] = array( '', cerber_table_view( 'Software errors', $err ) ); $php_err = 'SE  ' . count( $err_list ) . ''; } } $request_details = ''; $more_link = ''; $toggle_class = ''; if ( $more_details ) { foreach ( $more_details as $d ) { if ( $d[0] ) { $request_details .= '

' . $d[0] . '

' . $d[1] . '
'; } else { $request_details .= $d[1]; } } $more_link = 'Details'; $toggle_class = 'crb-toggle'; } $request = '' . $row_uri . '' . '

' . $row->request_method . ' ' . $f . $wp_type . ' HTTP ' . $row->http_code . ' ' . get_status_header_desc( $row->http_code ) . ' ' . $php_err . ' ' . $processing . ' ' . $more_link . ' ' . $activity . '

' . $wp_obj; // Decorating this table can't be done via simple CSS if ( ! empty( $even ) ) { $class = 'crb-even'; $even = false; } else { $even = true; $class = 'crb-odd'; } $tbody .= ' ' . $date . ' ' . $request . '
' . $ip . '
' . $hostname . $country . ' ' . cerber_detect_browser( $details[1] ) . ' ' . $name . ''; $tbody .= '
' . $request_details . '
'; } $heading = array( __( 'Date', 'wp-cerber' ), __( 'Request', 'wp-cerber' ), '
' . __( 'IP Address', 'wp-cerber' ), __( 'Host Info', 'wp-cerber' ), __( 'User Agent', 'wp-cerber' ), __( 'Local User', 'wp-cerber' ), ); $titles = '' . implode( '', $heading ) . ''; $table = '' . $titles . '' . $titles . '' . $tbody . '
'; if ( empty( $args['no_navi'] ) ) { $table .= cerber_page_navi( $total, $per_page ); } //$legend = '

'.sprintf(__('Showing last %d records from %d','wp-cerber'),count($rows),$total); //if (empty($args['no_export'])) $export_link = ' '.__('Export','wp-cerber').''; } else { $table = '

'.__('No requests have been logged.','wp-cerber').'

'; cerber_watchdog( true ); } if ( empty( $args['no_navi'] ) ) { $filters = array(); $filters[] = array( '', __( 'All requests', 'wp-cerber' ) ); $filters[] = array( '&filter_set=1', __( 'Suspicious activity', 'wp-cerber' ) ); $filters[] = array( '&filter_http_code=399&filter_http_code_mode=GT', __( 'Errors', 'wp-cerber' ) ); $filters[] = array( '&filter_user=*', __( 'Logged in users', 'wp-cerber' ) ); $filters[] = array( '&filter_user=0', __( 'Not logged in visitors', 'wp-cerber' ) ); $filters[] = array( '&filter_method=POST&filter_wp_type=519&filter_wp_type_mode=GT', __( 'Form submissions', 'wp-cerber' ) ); $filters[] = array( '&filter_http_code=404', __( 'Page Not Found', 'wp-cerber' ) ); $filters[] = array( '&filter_wp_type=520', 'REST API' ); $filters[] = array( '&filter_wp_type=515', 'XML-RPC' ); //$filters .= ' | Form submissions'; if ( $threshold = crb_get_settings( 'tithreshold' ) ) { $filters[] = array( '&filter_processing=' . $threshold, __( 'Longer than', 'wp-cerber' ) . ' ' . $threshold . ' ms' ); } $filter_links = ''; foreach ( $filters as $filter ) { $filter_links .= '' . $filter[1] . ''; } //$search_button = cerber_traffic_search_form(); $search_button = ' '.__('Advanced Search','wp-cerber').''; $export_button .= ' ' . __( 'Export', 'wp-cerber' ) . ''; $right_links = $search_button .' '. $export_button; $refresh = ''; if ( crb_get_settings( 'timode' ) ) { $refresh = '    ' . __( 'Refresh', 'wp-cerber' ) . ''; } $top_bar = '
' . $filter_links . $refresh . '
' . $right_links . '

'; $ret = '
' . $top_bar . crb_admin_traffic_search_form() . $info . '
' . $ret; } $ret .= $table; if ( ! crb_get_settings( 'timode' ) ) { $ret = '

Logging is currently disabled, you are viewing historical information.

' . $ret; } if ($echo) echo $ret; else return $ret; } /** * Create a table view of an array to display it * * @param $title * @param $fields * * @return string */ function cerber_table_view( $title, $fields, $sub_key = null ) { if ( empty( $fields ) ) { return ''; } if ( ! isset( $sub_key ) ) { $class = 'crb-fields-table crb-top-table'; } else { $class = 'crb-fields-table crb-sub-table'; } $view = ''; if ( $title ) { $view .= ''; } $i = 1; foreach ( $fields as $key => $value ) { if ( is_array( $value ) ) { $view .= ''; } else { $view .= ''; } $i ++; } $view .= '
' . $title . '
' . $key . '' . cerber_table_view( '', $value, $key ) . '
' . htmlentities( $key ) . '
' . nl2br( htmlentities( $value ) ) . '
'; return $view; } /** * Parse arguments and create SQL query for retrieving rows from the traffic table * * @param array $args Optional arguments to use them instead of using $_GET * * @return array * @since 6.0 */ function cerber_traffic_query( $args = array() ) { global $wpdb; $ret = array_fill( 0, 8, '' ); $where = array(); $join = ''; $join_act = false; $q = crb_admin_parse_query( array( 'filter_sid', 'filter_http_code', 'filter_http_code_mode', 'filter_ip', 'filter_processing', 'filter_user', 'filter_user_alt', 'filter_user_mode', 'filter_wp_type', 'filter_wp_type_mode', 'search_traffic', 'filter_method', 'filter_activity', 'filter_set', 'filter_errors', ), $args ); if ( preg_match( '/^\w+$/', $q->filter_sid ) ) { $where[] = 'log.session_id = "' . $q->filter_sid . '"'; } $falist = array(); if ( $q->filter_http_code ) { // Multiple codes can be requested this way: &filter_http_code[]=404&filter_http_code[]=405 if ( is_array( $q->filter_http_code ) ) { $falist = array_filter( array_map( 'absint', $q->filter_http_code ) ); $where[] = 'log.http_code IN (' . implode( ',', $falist ) . ')'; } else { $filter = absint( $q->filter_http_code ); $op = '='; if ( $q->filter_http_code_mode == 'GT' ) { $op = '>'; } $where[] = 'log.http_code ' . $op . $filter; $falist = array( $filter ); // for further using in links } } //$ret[3] = $falist; if ( $q->filter_ip ) { $range = cerber_any2range( $q->filter_ip ); if ( is_array( $range ) ) { $where[] = $wpdb->prepare( '(log.ip_long >= %d AND log.ip_long <= %d)', $range['begin'], $range['end'] ); } elseif ( cerber_is_ip_or_net( $q->filter_ip ) ) { $where[] = $wpdb->prepare( 'log.ip = %s', $q->filter_ip ); } else { $where[] = "log.ip = 'produce-no-result'"; } $ret[4] = preg_replace( CRB_IP_NET_RANGE, '', $q->filter_ip ); } if ( $q->filter_processing ) { $p = absint( $q->filter_processing ); $where[] = 'log.processing > ' . $p; $ret[5] = $p; } $filter_user = false; if ( $q->filter_user !== false ) { $filter_user = $q->filter_user; } elseif ( $q->filter_user_alt !== false ) { $filter_user = $q->filter_user_alt; } if ( $filter_user !== false ) { if ( $filter_user == '*' ) { $um = ( ! empty( $q->filter_user_mode ) ) ? '=' : '!='; $where[] = 'log.user_id ' . $um . ' 0'; $ret[6] = '*'; } elseif ( preg_match_all( '/\d+/', $filter_user, $matches ) ) { $ul = implode( ',', $matches[0] ); if ( ! empty( $q->filter_user_mode ) ) { $um = 'NOT IN'; } else { $um = 'IN'; $ret[6] = $ul; } $where[] = 'log.user_id ' . $um . ' (' . $ul . ')'; } } if ( $q->filter_wp_type ) { $t = absint( $q->filter_wp_type ); $ret[7] = $t; $op = '='; if ( $q->filter_wp_type_mode == 'GT' ) { $op = '>'; } $where[] = 'log.wp_type ' . $op . $t; } if ( $q->search_traffic ) { $search = stripslashes_deep( $q->search_traffic ); if ( $search['ip'] ) { if ( $ip = filter_var( $search['ip'], FILTER_VALIDATE_IP ) ) { $where[] = 'log.ip = "' . $ip . '"'; } else { $where[] = 'log.ip LIKE "%' . cerber_real_escape( $search['ip'] ) . '%"'; } } if ( $search['uri'] ) { $where[] = 'log.uri LIKE "%' . cerber_real_escape( $search['uri'] ) . '%"'; } if ( $search['fields'] ) { $where[] = 'log.request_fields LIKE "%' . cerber_real_escape( $search['fields'] ) . '%"'; } if ( $search['details'] ) { $where[] = 'log.request_details LIKE "%' . cerber_real_escape( $search['details'] ) . '%"'; } if ( $search['date_from'] ) { if ( $stamp = strtotime( 'midnight ' . $search['date_from'] ) ) { $gmt_offset = get_option( 'gmt_offset' ) * 3600; $where[] = 'log.stamp >= ' . ( absint( $stamp ) - $gmt_offset ); } } if ( $search['date_to'] ) { if ( $stamp = strtotime( 'midnight ' . $search['date_to'] ) ) { $gmt_offset = get_option( 'gmt_offset' ) * 3600; $where[] = 'log.stamp <= ' . ( absint( $stamp ) - $gmt_offset ); } } if ( ! $q->filter_errors && $search['errors'] ) { $where[] = 'log.php_errors LIKE "%' . cerber_real_escape( $search['errors'] ) . '%"'; } } if ( $q->filter_method ) { $where[] = $wpdb->prepare( 'log.request_method = %s', $q->filter_method ); } $activity = null; if ( $q->filter_activity ) { $activity = absint( $q->filter_activity ); } if ( $q->filter_set ) { switch ( $q->filter_set ) { case 1: $activity = implode( ',', crb_get_activity_set( 'suspicious' ) ); break; } } if ( $activity ) { $ret[3] = $activity; $where[] = 'act.activity IN (' . $activity . ')'; $join_act = true; } if ( $q->filter_errors ) { $where[] = 'log.php_errors != ""'; } // --------------------------------------------------------------------------------- $where = ( ! empty( $where ) ) ? 'WHERE ' . implode( ' AND ', $where ) : ''; // Limits, if specified if ( isset( $args['per_page'] ) ) { $per_page = $args['per_page']; } else { $per_page = crb_admin_get_per_page(); } $per_page = absint( $per_page ); $ret[2] = $per_page; $cols = 'log.*'; if ( ! empty( $args['columns'] ) ) { $cols = ''; foreach ( $args['columns'] as $col_name ) { $cols .= ',log.' . preg_replace( '/[^A-Z_\d]/i', '', $col_name ); } $cols = trim( $cols, ',' ); } if ( $join_act ) { $join = ' JOIN ' . CERBER_LOG_TABLE . ' act ON (log.session_id = act.session_id)'; } if ( $per_page ) { $limit = ' LIMIT ' . ( cerber_get_pn() - 1 ) * $per_page . ',' . $per_page; //$ret[0] = 'SELECT SQL_CALC_FOUND_ROWS log.session_id,log.* FROM ' . CERBER_TRAF_TABLE . " log USE INDEX FOR ORDER BY (stamp) {$where} ORDER BY stamp DESC {$limit}"; $ret[0] = 'SELECT log.session_id,'.$cols.' FROM ' . CERBER_TRAF_TABLE . " log {$join} {$where} ORDER BY log.stamp DESC {$limit}"; //$ret[0] = 'SELECT SQL_CALC_FOUND_ROWS log.*,act.activity FROM ' . CERBER_TRAF_TABLE . ' log USE INDEX FOR ORDER BY (stamp) LEFT JOIN '.CERBER_LOG_TABLE." act ON (log.session_id = act.session_id) {$where} ORDER BY log.stamp DESC {$limit}"; } else { $ret[0] = 'SELECT log.session_id,'.$cols.' FROM ' . CERBER_TRAF_TABLE . " log {$join} {$where} ORDER BY stamp DESC"; // "ORDER BY" is mandatory! } $ret[1] = 'SELECT COUNT(log.stamp) FROM ' . CERBER_TRAF_TABLE . " log {$join} {$where}"; return $ret; } /** * Traffic Search form HTML * * @return string * */ function crb_admin_traffic_search_form() { ob_start(); ?> 'XML-RPC', 520 => 'REST API' ); if ( isset( $types[ $wp_type ] ) ) { return $types[ $wp_type ]; } return ''; } function cerber_get_err_type( $type ) { $list = array( 'E_ERROR', 'E_WARNING', 'E_PARSE', 'E_NOTICE', 'E_CORE_ERROR', 'E_CORE_WARNING', 'E_COMPILE_ERROR', 'E_COMPILE_WARNING', 'E_USER_ERROR', 'E_USER_WARNING', 'E_USER_NOTICE', 'E_STRICT', 'E_RECOVERABLE_ERROR', 'E_DEPRECATED', 'E_USER_DEPRECATED', 'E_ALL', ); return $list[ intval( log( $type, 2 ) ) ]; } /** * Check if admin AJAX is permitted. * */ function cerber_check_ajax_permissions( $strict = true ) { if ( nexus_is_valid_request() ) { /* $nonce = crb_array_get( nexus_request_data()->get_params, 'ajax_nonce' ); if ( ! $nonce ) { $nonce = nexus_request_data()->get_post_data( 'ajax_nonce' ); } if ( ! wp_verify_nonce( $nonce, 'crb-ajax-admin' ) ) { return false; } */ return true; } check_ajax_referer( 'crb-ajax-admin', 'ajax_nonce' ); if ( ! current_user_can( 'manage_options' ) ) { if ( $strict ) { wp_die( 'Oops! Access denied.' ); } return 0; } return true; } function crb_admin_allowed_ajax( $action ) { $list = array( 'cerber_ajax', 'cerber_scan_control', 'cerber_ref_upload', 'cerber_view_file', 'cerber_scan_bulk_files' ); return in_array( $action, $list ); } function crb_is_task_permitted( $die = false ) { if ( is_super_admin() || nexus_is_valid_request() ) { return true; } if ( $die ) { wp_die( 'Oops! Access denied.' ); } return false; } /** * Identify and render Cerber's admin page * * @param string $page_id * @param string $active_tab */ function cerber_render_admin_page( $page_id = '', $active_tab = '' ) { if ( nexus_get_context() ) { nexus_show_remote_page(); return; } $error = ''; if ( $page = cerber_get_admin_page_config( $page_id ) ) { if ( ! empty( $page['pro'] ) && ! lab_lab() ) { $error = 'This feature requires the PRO version of the plugin.'; } else { if ( ( $tab_filter = crb_array_get( $page, 'tab_filter' ) ) && is_callable( $tab_filter ) ) { $page['tabs'] = call_user_func( $tab_filter, $page['tabs'] ); } cerber_show_admin_page( $page['title'], $page['tabs'], $active_tab, $page['callback'] ); } } else { $error = 'Unknown admin page: ' . htmlspecialchars( $page_id ); } if ( $error ) { echo '
ERROR: ' . $error . ' on ' . get_bloginfo( 'name' ) . '
'; } } function cerber_get_admin_page_config( $page = '' ) { if ( ! $page ) { if ( ! $page = crb_admin_get_page() ) { return false; } } if ( $config = crb_addon_admin_page( $page ) ) { return $config; } $admin_pages = array( 'cerber-security' => array( 'title' => 'WP Cerber Security', 'tabs' => array( 'dashboard' => array( 'bxs-dashboard', __( 'Dashboard', 'wp-cerber' ) ), 'activity' => array( 'bx-pulse', __( 'Activity', 'wp-cerber' ) ), 'sessions' => array( 'bx-group', __( 'Sessions', 'wp-cerber' ) ), 'lockouts' => array( 'bxs-shield', __( 'Lockouts', 'wp-cerber' ) ), 'main' => array( 'bx-slider', __( 'Main Settings', 'wp-cerber' ) ), 'acl' => array( 'bx-lock', __( 'Access Lists', 'wp-cerber' ) ), 'hardening' => array( 'bx-shield-alt', __( 'Hardening', 'wp-cerber' ) ), //'users' => array( 'bx-group', __( 'Users', 'wp-cerber' ) ), 'notifications' => array( 'bx-bell', __( 'Notifications', 'wp-cerber' ) ), ), 'tab_filter' => function ( $tabs ) { $blocked = cerber_blocked_num(); $acl = cerber_db_get_var( 'SELECT count(ip) FROM ' . CERBER_ACL_TABLE . ' WHERE acl_slice = 0' ); $uss = cerber_db_get_var( 'SELECT count(user_id) FROM ' . cerber_get_db_prefix() . CERBER_USS_TABLE ); $tabs['sessions'][1] .= ' ' . $uss . ''; $tabs['lockouts'][1] .= ' ' . $blocked . ''; $tabs['acl'][1] .= ' ' . $acl . ''; return $tabs; }, 'callback' => function ( $tab ) { switch ( $tab ) { case 'acl': cerber_acl_form(); break; case 'activity': cerber_show_activity(); break; case 'sessions': crb_admin_show_sessions(); break; case 'lockouts': cerber_show_lockouts(); break; case 'help': cerber_show_help(); break; case 'dashboard': cerber_show_dashboard(); break; default: cerber_show_settings_form( $tab ); } } ), 'cerber-recaptcha' => array( 'title' => __( 'Anti-spam and bot detection settings', 'wp-cerber' ), 'tabs' => array( 'antispam' => array( 'bx-chip', __( 'Anti-spam engine', 'wp-cerber' ) ), 'captcha' => array( 'bxl-google', 'reCAPTCHA' ), ), 'callback' => function ( $tab ) { switch ( $tab ) { case 'captcha': $group = 'recaptcha'; break; default: $group = 'antispam'; } cerber_show_settings_form( $group ); } ), 'cerber-traffic' => array( 'title' => __( 'Traffic Inspector', 'wp-cerber' ), 'tabs' => array( 'traffic' => array( 'bx-show', __( 'Live Traffic', 'wp-cerber' ) ), 'ti_settings' => array( 'bx-slider', __( 'Settings', 'wp-cerber' ) ), ), 'callback' => function ( $tab ) { switch ( $tab ) { case 'ti_settings': cerber_show_settings_form( 'traffic' ); break; default: cerber_show_traffic(); } } ), 'cerber-shield' => array( 'title' => __( 'Data Shield Policies', 'wp-cerber' ), 'tabs' => array( 'user_shield' => array( 'bx-group', __( 'Accounts & Roles', 'wp-cerber' ) ), 'opt_shield' => array( 'bx-slider', __( 'Site Settings', 'wp-cerber' ) ), ), 'callback' => function ( $tab ) { cerber_show_settings_form( $tab ); } ), 'cerber-users' => array( 'title' => __( 'User Policies', 'wp-cerber' ), 'tabs' => array( 'role_policies' => array( 'bx-group', __( 'Role-based', 'wp-cerber' ) ), 'global_policies' => array( 'bx-user-detail', __( 'Global', 'wp-cerber' ) ), ), 'callback' => function ( $tab ) { switch ( $tab ) { case 'role_policies': crb_admin_show_role_policies(); break; case 'global_policies': cerber_show_settings_form( 'users' ); break; default: cerber_show_settings_form( $tab ); } } ), 'cerber-rules' => array( 'pro' => 1, 'title' => __( 'Security Rules', 'wp-cerber' ), 'tabs' => array( 'geo' => array( 'bxs-world', __( 'Countries', 'wp-cerber' ) ), ), 'callback' => function ( $tab ) { switch ( $tab ) { case 'geo': crb_admin_show_geo_rules(); break; default: crb_admin_show_geo_rules(); } } ), 'cerber-integrity' => array( 'title' => __( 'Site Integrity', 'wp-cerber' ), 'tabs' => array( 'scan_main' => array( 'bx-radar', __( 'Security Scanner', 'wp-cerber' ) ), 'scan_settings' => array( 'bxs-slider-alt', __( 'Settings', 'wp-cerber' ) ), 'scan_schedule' => array( 'bx-time', __( 'Scheduling', 'wp-cerber' ) ), 'scan_policy' => array( 'bx-bolt', __( 'Cleaning up', 'wp-cerber' ) ), 'scan_ignore' => array( 'bx-hide', __( 'Ignore List', 'wp-cerber' ) ), 'scan_quarantine' => array( 'bx-trash', __( 'Quarantine', 'wp-cerber' ) ), ), 'callback' => function ( $tab ) { switch ( $tab ) { case 'scan_settings': cerber_show_settings_form( 'scanner' ); break; case 'scan_schedule': cerber_show_settings_form( 'schedule' ); break; case 'scan_policy': cerber_show_settings_form( 'policies' ); break; case 'scan_quarantine': cerber_show_quarantine(); break; case 'scan_ignore': cerber_show_ignore(); break; case 'help': cerber_show_help(); break; default: cerber_show_scanner(); } } ), 'cerber-tools' => array( 'title' => __( 'Tools', 'wp-cerber' ), 'tabs' => array( 'imex' => array( 'bx-layer', __( 'Export & Import', 'wp-cerber' ) ), 'diagnostic' => array( 'bx-wrench', __( 'Diagnostic', 'wp-cerber' ) ), 'diag-log' => array( 'bx-bug', __( 'Log', 'wp-cerber' ) ), 'change-log' => array( 'bx-collection', __( 'Changelog', 'wp-cerber' ) ), 'license' => array( 'bx-key', __( 'License', 'wp-cerber' ) ), ), 'callback' => function ( $tab ) { switch ( $tab ) { case 'diagnostic': cerber_show_diag(); break; case 'license': cerber_show_lic(); break; case 'diag-log': cerber_show_diag_log(); break; case 'change-log': cerber_show_change_log(); break; case 'help': cerber_show_help(); break; default: if ( ! nexus_is_valid_request() ) { cerber_show_imex(); } else { echo 'This admin page is not available in this mode.'; } } } ), ); return crb_array_get( $admin_pages, $page ); } function crb_admin_parse_query( $fields, $alt = array() ) { $arr = crb_get_query_params(); $ret = array(); foreach ( $fields as $field ) { if ( isset( $alt[ $field ] ) ) { $val = $alt[ $field ]; } else { $val = crb_array_get( $arr, $field, false ); } if ( is_array( $val ) ) { $val = array_map( 'trim', $val ); } elseif ( $val !== false ) { $val = trim( $val ); } $ret[ $field ] = $val; } return (object) $ret; } function crb_admin_get_page() { if ( nexus_is_valid_request() ) { $page = nexus_request_data()->page; } else { $page = cerber_get_get( 'page', '[A-Z0-9\_\-]+' ); } return $page; } function crb_admin_get_tab( $tabs = array() ) { if ( nexus_is_valid_request() ) { $tab = nexus_request_data()->tab; } else { $tab = cerber_get_get( 'tab', '[\w\-]+' ); } if ( empty( $tabs ) ) { return $tab; } $tabs['help'] = 1; // always must be in the array if ( ! $tab || ! isset( $tabs[ $tab ] ) ) { reset( $tabs ); $tab = key( $tabs ); } return $tab; } function cerber_show_tabs( $active, $tabs = array() ) { echo ''; } // Access Lists (ACL) --------------------------------------------------------- /** * @param string $ip * @param string $tag * @param string $comment * @param int $acl_slice * * @return bool|WP_Error */ function cerber_acl_add( $ip, $tag, $comment = '', $acl_slice = 0 ) { global $wpdb; $ip = trim( $ip ); $acl_slice = absint( $acl_slice ); $v6range = ''; $ver6 = 0; if ( cerber_is_ipv4( $ip ) ) { $begin = ip2long( $ip ); $end = ip2long( $ip ); } elseif ( cerber_is_ipv6( $ip ) ) { $ip = cerber_ipv6_short( $ip ); list( $begin, $end, $v6range ) = crb_ipv6_prepare( $ip, $ip ); $ver6 = 1; } elseif ( ( $range = cerber_any2range( $ip ) ) && is_array( $range ) ) { $ver6 = $range['IPV6']; $begin = $range['begin']; $end = $range['end']; $v6range = $range['IPV6range']; } else { return new WP_Error( 'acl_wrong_ip', __( 'Incorrect IP address or IP range', 'wp-cerber' ) . ' ' . $ip ); } if ( cerber_db_get_var( 'SELECT ip FROM ' . CERBER_ACL_TABLE . ' WHERE acl_slice = ' . $acl_slice . ' AND ver6 = ' . $ver6 . ' AND ip_long_begin = ' . $begin . ' AND ip_long_end = ' . $end . ' AND v6range = "' . $v6range . '" LIMIT 1' ) ) { return new WP_Error( 'acl_wrong_ip', __( 'The IP address you are trying to add is already in the list', 'wp-cerber' ) ); } $result = $wpdb->insert( CERBER_ACL_TABLE, array( 'ip' => $ip, 'ip_long_begin' => $begin, 'ip_long_end' => $end, 'tag' => $tag, 'comments' => $comment, 'acl_slice' => $acl_slice, 'v6range' => $v6range, 'ver6' => $ver6, ), array( '%s', '%d', '%d', '%s', '%s', '%d', '%s', '%d' ) ); if ( ! $result ) { return new WP_Error( 'acl_db_error', $wpdb->last_error ); } crb_event_handler( 'ip_event', array( 'e_type' => 'acl_add', 'ip' => $ip, 'tag' => $tag, 'slice' => $acl_slice, 'comments' => $comment, ) ); return true; } function cerber_add_white( $ip, $comment = '' ) { return cerber_acl_add( $ip, 'W', $comment ); } function cerber_add_black( $ip, $comment = '' ) { return cerber_acl_add( $ip, 'B', $comment ); } function cerber_acl_remove( $ip, $acl_slice = 0 ) { if ( ! is_numeric( $acl_slice ) ) { return false; } $acl_slice = absint( $acl_slice ); $ip = preg_replace( CRB_IP_NET_RANGE, ' ', $ip ); $ret = cerber_db_query( 'DELETE FROM ' . CERBER_ACL_TABLE . ' WHERE acl_slice = ' . $acl_slice . ' AND ip = "' . $ip . '"' ); crb_event_handler( 'ip_event', array( 'e_type' => 'acl_remove', 'ip' => $ip, 'slice' => $acl_slice, 'result' => $ret ) ); return $ret; } /** * Can a given IP be added to the blacklist * * @param $ip string A candidate to be added to the list * @param $list string * * @return bool True if IP can be listed */ function cerber_can_be_listed( $ip, $list = 'B' ) { if ( $list == 'B' ) { $admin_ip = cerber_get_remote_ip(); if ( cerber_is_ip( $ip ) ) { if ( $admin_ip == cerber_ipv6_short( $ip ) ) { return false; } return true; } // $ip = range if ( crb_acl_is_white( $admin_ip ) ) { return true; } if ( ! $range = cerber_any2range( $ip ) ) { return false; } if ( cerber_is_ip_in_range( $range, $admin_ip ) ) { return false; } return true; } return true; } /** * Bulk action for WP_List_Table * * @return bool|array|string */ function cerber_get_bulk_action() { // GET if ( cerber_is_http_get() ) { if ( ( $ac = crb_get_query_params( 'action', '[\w\-]+' ) ) && $ac != '-1' ) { return $ac; } if ( ( $ac = crb_get_query_params( 'action2', '[\w\-]+' ) ) && $ac != '-1' ) { return $ac; } return false; } // POST if ( ( $ac = crb_get_post_fields( 'action', false, '[\w\-]+' ) ) && $ac != '-1' ) { return $ac; } if ( ( $ac = crb_get_post_fields( 'action2', false, '[\w\-]+' ) ) && $ac != '-1' ) { return $ac; } return false; } function crb_admin_cool_features() { return '
' . __( 'These features are available in a professional version of the plugin.', 'wp-cerber' ) . '

' . __( 'Know more about all advantages at', 'wp-cerber' ) . ' https://wpcerber.com/pro/
'; } /** * @param string $url * @param string $ancor * @param string $msg * * @return string */ function crb_confirmation_link( $url, $ancor, $msg = '' ) { if ( ! $msg ) { $msg = __( 'Are you sure?', 'wp-cerber' ); } return '' . $ancor . ''; } // Setting up menu editor ----------------------------------------------------- add_action( 'admin_head-nav-menus.php', function () { add_meta_box( 'wp_cerber_nav_menu', 'WP Cerber', 'cerber_nav_menu_box', 'nav-menus', 'side', 'low' ); } ); function cerber_nav_menu_box() { // Warning: do not change array indexes $list = array( 'login-url' => __( 'Log In', 'wp-cerber' ), 'logout-url' => __( 'Log Out', 'wp-cerber' ), 'reg-url' => __( 'Register', 'wp-cerber' ), ); if ( class_exists( 'WooCommerce' ) ) { $list['wc-login-url'] = __( 'WooCommerce Log In', 'wp-cerber' ); $list['wc-logout-url'] = __( 'WooCommerce Log Out', 'wp-cerber' ); } ?>