ID ); $selected = ( empty( $cus['tfm'] ) ) ? 0 : $cus['tfm']; echo cerber_select( 'cerber_user_2fa', array( 0 => __( 'Determined by user role policies', 'wp-cerber' ), 1 => __( 'Always enabled', 'wp-cerber' ), 2 => __( 'Disabled', 'wp-cerber' ), ), $selected ); ?> ID ); $b_msg = ( ! empty( $b['blocked_msg'] ) ) ? $b['blocked_msg'] : ''; $b_note = ( ! empty( $b['blocked_note'] ) ) ? $b['blocked_note'] : ''; $dsp = ( ! $b ) ? 'display:none;' : ''; ?>
ID ); if ( $pin ) : ?> add( 'invalid-email', 'Invalid email address for Two-factor authentication' ); } ); } } else { $cus['tfemail'] = ''; } cerber_update_set( 'cerber_user', $cus, $user_id ); if ( $cus['tfm'] == 2 ) { CRB_2FA::delete_2fa( $user_id ); } } add_filter( 'user_row_actions', 'crb_collect_uids', 10, 2 ); add_filter( 'ms_user_row_actions', 'crb_collect_uids', 10, 2 ); function crb_collect_uids( $actions, $user_object ) { crb_user_id_list( $user_object->ID ); return $actions; } function crb_user_id_list( $uid = 0 ) { static $list = array(); if ( $uid ) { $list[ $uid ] = $uid; } else { return $list; } } add_filter( 'views_users', function ( $views ) { global $wpdb; $c = cerber_db_get_var( 'SELECT COUNT(meta_key) FROM ' . $wpdb->usermeta . ' WHERE meta_key = "' . CERBER_BUKEY . '"' ); $t = __( 'Blocked Users', 'wp-cerber' ); if ( $c ) { $t = '' . $t . ''; } $views['cerber_blocked'] = $t . ' (' . $c . ')'; return $views; } ); add_filter( 'users_list_table_query_args', function ( $args ) { if ( isset( $_REQUEST['crb_filter_users'] ) ) { $args['meta_key'] = CERBER_BUKEY; $args['meta_compare'] = 'EXISTS'; } return $args; } ); function crb_format_user_name( $data ) { if ( $data->first_name ) { $ret = $data->first_name . ' ' . $data->last_name; } else { $ret = $data->display_name; } return $ret . ' (' . $data->user_login . ')'; } // Bulk actions add_filter( "bulk_actions-users", function ( $actions ) { $actions['cerber_block_users'] = __( 'Block', 'wp-cerber' ); return $actions; } ); add_filter( "handle_bulk_actions-users", function ( $url ) { if ( cerber_get_bulk_action() == 'cerber_block_users' ) { if ( $users = cerber_get_get( 'users', '\d+' ) ) { foreach ( $users as $user_id ) { cerber_block_user( absint( $user_id ) ); } } else { // 'No users selected'; } $preserve = array( 's', 'paged', 'role', 'crb_filter_users' ); $remove = array_diff( array_keys( crb_get_query_params() ), $preserve ); $url = remove_query_arg( $remove, $url ); } return $url; } ); function cerber_block_user( $user_id, $msg = '', $note = '' ) { if ( ! is_super_admin() ) { return; } if ( $user_id == get_current_user_id() ) { return; } if ( ( $m = get_user_meta( $user_id, CERBER_BUKEY, true ) ) && ! empty( $m['blocked'] ) && $m[ 'u' . $user_id ] == $user_id && $m['blocked_msg'] == $msg && $m['blocked_note'] == $note ) { return; } if ( ! $m || ! is_array( $m ) ) { $m = array(); } if ( empty( $m['blocked'] ) ) { $m['blocked_time'] = time(); $m['blocked'] = 1; $m[ 'u' . $user_id ] = $user_id; $m['blocked_by'] = get_current_user_id(); $m['blocked_ip'] = cerber_get_remote_ip(); } $m['blocked_msg'] = $msg; $m['blocked_note'] = $note; update_user_meta( $user_id, CERBER_BUKEY, $m ); crb_admin_destroy( $user_id ); } function crb_admin_show_role_policies() { $roles = wp_roles(); $tabs_config = array(); $policies = crb_get_settings( 'crb_role_policies' ); foreach ( $roles->role_names as $role_id => $name ) { $tabs_config[ $role_id ] = array( 'title' => $name, //'desc' => $info, 'content' => crb_admin_role_form( $role_id, crb_array_get( $policies, $role_id ) ), ); } crb_admin_show_vtabs( $tabs_config, __( 'Save All Changes', 'wp-cerber' ), array( 'cerber_admin_do' => 'update_role_policies' ) ); } function crb_admin_role_form( $role_id, $values ) { $html = ''; foreach ( crb_admin_role_config() as $section_id => $config ) { foreach ( $config['fields'] as $field_id => $field ) { $pro = ( isset( $field['pro'] ) && ! lab_lab() ); if ( empty( $field['disabled'] ) ) { $field['disabled'] = ( crb_array_get( $field, 'disable_role' ) == $role_id ); } if ( $field_id == '2famode' && $role_id == 'administrator' ) { $field['disabled'] = ! cerber_2fa_checker(); } $enabler = ''; if ( isset( $field['enabler'][0] ) ) { $enabler .= ' data-enabler="crb-input-' . $role_id . '[' . $field['enabler'][0] . ']" '; } if ( isset( $field['enabler'][1] ) ) { $enabler .= ' data-enabler_value="' . $field['enabler'][1] . '" '; } $s = ( $pro ) ? ' color: #888; ' : ''; // Enabling/disabling conditional inputs $enabled = true; if ( isset( $field['enabler'][0] ) ) { $enab_val = crb_array_get( $values, $field['enabler'][0], '' ); if ( isset( $field['enabler'][1] ) ) { if ( $enab_val != $field['enabler'][1] ) { $enabled = false; } } else { if ( empty( $enab_val ) ) { $enabled = false; } } } $tr_class = ( ! $enabled ) ? ' crb-disable-this' : ''; if ( ! empty( $field['disabled'] ) ) { $tr_class .= ' crb-disabled'; } if ( $field['type'] != 'html' ) { $value = ( ! $pro ) ? crb_array_get( $values, $field_id, '' ) : ''; $html .= ''; } else { $t = ( $pro && $field_id == '2fasmart' ) ? crb_admin_cool_features() : ''; $html .= ''; } } } $html .= '
' . $field['title'] . '' . crb_admin_form_field( $field, $role_id . '[' . $field_id . ']', $value ) . '
' . $t . $field['title'] . '
'; return $html; } function crb_admin_form_field( $field, $name, $value, $id = '' ) { $value = crb_attr_escape( $value ); $label = crb_array_get( $field, 'label' ); if ( ! $id ) { $id = 'crb-input-' . $name; } $atts = ''; if ( $field['disabled'] || ( isset( $field['pro'] ) && ! lab_lab() ) ) { $atts = ' disabled '; } if ( $field['disabled'] ) { $value = ''; } if ( isset( $field['placeholder'] ) ) { $atts .= ' placeholder="' . $field['placeholder'] . '"'; } $style = ''; if ( isset( $field['width'] ) ) { $style .= ' width:' . $field['width']; } switch ( $field['type'] ) { case 'checkbox': return cerber_checkbox( $name, $value, $label, $id, $atts ); break; case 'select': return cerber_select( $name, $field['set'], $value, '', $id, '', '', null, $atts ); break; case 'text': default: $type = crb_array_get( $field, 'type', 'text' ); //return $pre . ''; return ''; break; } } function crb_admin_role_config() { return array( 'access' => array( 'name' => '', 'desc' => '', 'fields' => array( 'nodashboard' => array( 'title' => __( 'Block access to WordPress Dashboard', 'wp-cerber' ), 'type' => 'checkbox', 'disable_role' => 'administrator', ), 'notoolbar' => array( 'title' => __( 'Hide Toolbar when viewing site', 'wp-cerber' ), 'type' => 'checkbox', ), ) ), 'redirect' => array( 'name' => __( 'Redirection rules', 'wp-cerber' ), 'desc' => '', 'fields' => array( 'rdr_login' => array( 'title' => __( 'Redirect user after login', 'wp-cerber' ), 'type' => 'text', 'width' => '100%', ), 'rdr_logout' => array( 'title' => __( 'Redirect user after logout', 'wp-cerber' ), 'type' => 'text', 'width' => '100%', ), ) ), 'misc' => array( 'name' => '', 'desc' => '', 'fields' => array( 'auth_expire' => array( 'title' => __( 'User session expiration time', 'wp-cerber' ), 'placeholder' => 'minutes', 'type' => 'number', ), ) ), 'twofactor' => array( 'name' => __( 'Two-Factor Authentication', 'wp-cerber' ), 'desc' => '', 'fields' => array( '2famode' => array( 'title' => __( 'Two-factor authentication', 'wp-cerber' ), 'type' => 'select', 'set' => array( 0 => __( 'Disabled', 'wp-cerber' ), 1 => __( 'Always enabled', 'wp-cerber' ), 2 => __( 'Advanced mode', 'wp-cerber' ) ), ), '2fasmart' => array( 'title' => __( 'Enforce two-factor authentication if any of the following conditions is true', 'wp-cerber' ), 'type' => 'html', 'enabler' => array( '2famode', 2 ), 'pro' => 1 ), '2fanewcountry' => array( 'title' => __( 'Login from a different country', 'wp-cerber' ), 'type' => 'checkbox', 'enabler' => array( '2famode', 2 ), 'pro' => 1 ), '2fanewnet4' => array( 'title' => __( 'Login from a different network Class C', 'wp-cerber' ), 'type' => 'checkbox', 'enabler' => array( '2famode', 2 ), 'pro' => 1 ), '2fanewip' => array( 'title' => __( 'Login from a different IP address', 'wp-cerber' ), 'type' => 'checkbox', 'enabler' => array( '2famode', 2 ), 'pro' => 1 ), '2fanewua' => array( 'title' => __( 'Using a different browser or device', 'wp-cerber' ), 'type' => 'checkbox', 'enabler' => array( '2famode', 2 ), 'pro' => 1 ), 'note2' => array( 'title' => __( 'Enforce two-factor authentication with fixed intervals', 'wp-cerber' ), 'type' => 'html', 'enabler' => array( '2famode', 2 ), 'pro' => 1 ), '2fadays' => array( 'title' => __( 'Regular time intervals (days)', 'wp-cerber' ), 'type' => 'number', 'label' => __( 'days interval', 'wp-cerber' ), 'enabler' => array( '2famode', 2 ), 'pro' => 12 ), '2falogins' => array( 'title' => __( 'Fixed number of logins', 'wp-cerber' ), 'type' => 'number', 'label' => __( 'number of logins', 'wp-cerber' ), 'enabler' => array( '2famode', 2 ), 'pro' => 1 ), ) ), ); } function crb_admin_save_role_policies( $post ) { $roles = wp_roles(); $policies = array(); foreach ( $roles->role_names as $role_id => $name ) { $policies[ $role_id ] = $post[ $role_id ]; } array_walk_recursive( $policies, function ( &$element, $key ) { $element = trim( $element ); if ( $key == 'rdr_logout' ) { if ( false !== strrpos( $element, 'wp-admin' ) ) { $element = ''; } } if ( $element && in_array( $key, array( 'rdr_login', 'rdr_logout' ) ) ) { if ( substr( $element, 0, 4 ) != 'http' && $element[0] != '/' ) { $element = '/' . $element; } } if ( ! is_array( $element ) && ! is_numeric( $element ) ) { $element = sanitize_text_field( (string) $element ); } } ); $settings = get_site_option( CERBER_SETTINGS ); $settings['crb_role_policies'] = $policies; if ( cerber_update_site_option( CERBER_SETTINGS, $settings ) ) { cerber_admin_message( __( 'Policies have been updated', 'wp-cerber' ) ); } } /** * @param array|string $sids * @param int $user_id * * @return int */ function crb_admin_kill( $sids, $user_id = null ) { if ( ! is_super_admin() && ! nexus_is_valid_request() ) { return 0; } if ( ! is_array( $sids ) ) { $sids = array( $sids ); } if ( ! $user_id ) { $users = cerber_db_get_col( 'SELECT user_id FROM ' . cerber_get_db_prefix() . CERBER_USS_TABLE . ' WHERE wp_session_token IN ("' . implode( '","', $sids ) . '")' ); } else { $users = array( $user_id ); } if ( ! $users || ! $sids ) { return 0; } $kill = array_flip( $sids ); $total = 0; $errors = 0; // Prevent termination the current admin session if ( wp_get_session_token() ) { unset( $kill[ crb_admin_hash_token( wp_get_session_token() ) ] ); } $before = cerber_db_get_var( 'SELECT COUNT(user_id) FROM ' . cerber_get_db_prefix() . CERBER_USS_TABLE ); foreach ( $users as $user_id ) { $count = 0; $sessions = get_user_meta( $user_id, 'session_tokens', true ); if ( empty( $sessions ) || ! is_array( $sessions ) ) { continue; } if ( ! $do_this = array_intersect_key( $kill, $sessions ) ) { continue; } foreach ( $do_this as $key => $nothing ) { unset( $sessions[ $key ] ); unset( $kill[ $key ] ); $count ++; } if ( $count ) { if ( update_user_meta( $user_id, 'session_tokens', $sessions ) ) { $total += $count; } else { $errors ++; } } } if ( $errors ) { cerber_admin_notice( 'Error: Unable to update user meta data.' ); } if ( $total ) { cerber_admin_message( sprintf( _n( 'Session has been terminated', '%s sessions have been terminated', $total, 'wp-cerber' ), $total ) ); // Workaround if user meta cache is out-of-sync with DB (like with WP Redis) $after = cerber_db_get_var( 'SELECT count(user_id) FROM ' . cerber_get_db_prefix() . CERBER_USS_TABLE ); if ( $after == $before ) { // cache was not saved to DB cerber_sync_sessions(); } } else { cerber_admin_notice( 'No sessions found.' ); cerber_sync_sessions(); } return $total; } function crb_admin_destroy( $user_id ) { if ( ! $user_id || get_current_user_id() == $user_id ) { return; } $manager = WP_Session_Tokens::get_instance( $user_id ); $manager->destroy_all(); } /** * Return a "session verifier" to identify the current admin session among others admin sessions * * Copy of WP_Session_Tokens->hash_token(); * * @param $token * * @return string */ function crb_admin_hash_token( $token ) { // If ext/hash is not present, use sha1() instead. if ( function_exists( 'hash' ) ) { return hash( 'sha256', $token ); } else { return sha1( $token ); } } function crb_admin_is_current_session( $session_id ) { static $st = null; if ( $st === null ) { $st = wp_get_session_token(); } return ( $session_id === crb_admin_hash_token( $st ) ); } function crb_admin_get_user_cell( $user_id = null, $base_url = '', $text = '', $label = '' ) { static $roles, $user_cache = array(), $avatar_cache = array(); if ( ! $user_id ) { return ''; } if ( ! isset( $user_cache[ $user_id ] ) ) { $user_cache[ $user_id ] = get_userdata( $user_id ); } if ( ! isset( $avatar_cache[ $user_id ] ) ) { $avatar_cache[ $user_id ] = get_avatar( $user_id, 32 ); } if ( ! isset( $roles ) ) { $roles = wp_roles()->roles; } $ret = ''; if ( $u = $user_cache[ $user_id ] ) { $r = ''; if ( ! is_multisite() && $u->roles ) { $r = array(); foreach ( $u->roles as $role ) { $r[] = $roles[ $role ]['name']; } $r = '' . implode( ', ', $r ) . ''; } $lbl = ( $label ) ? '' . $label . '' : ''; if ( $base_url ) { $ret = '' . $u->display_name . '' . $lbl . '

' . $r . '

'; } else { $ret = '' . $u->display_name . '' . $lbl . '

' . $r . '

'; } $ret = '
' . $ret . '
'; if ( $avatar = $avatar_cache[ $user_id ] ) { $avatar = '' . $avatar . ''; } else { $avatar = ''; } $ret = '' . $avatar . '
' . $ret . $text . '
'; } return $ret; } function crb_admin_show_sessions() { // Helper for WP_List_Table URLs and navigation links if ( nexus_is_valid_request() ) { // Add parameters $add = array( 'paged', 'order', 'orderby' ); foreach ( $add as $param ) { //if ( $val = crb_array_get( crb_get_query_params(), $param ) ) { if ( $val = crb_get_query_params( $param ) ) { $_REQUEST[ $param ] = $val; $_GET[ $param ] = $val; } } // Correct URL add_filter( 'set_url_scheme', function ( $url, $scheme, $orig_scheme ) { return cerber_admin_link( 'sessions' ); }, 10, 3 ); } echo '
'; cerber_nonce_field( 'control', true ); echo ''; $slaves = new CRB_Sessions_Table(); $slaves->prepare_items(); //$slaves->search_box( 'Search', 'search_id' ); $slaves->display(); echo '
'; } // Personal data exporters ---------------------------------------- function crb_pdata_exporter_act( $email_address, $page = 1 ) { $per_page = 1000; // Rows per step (SQL query) $limit = ( $per_page * ( absint( $page ) - 1 ) ) . ',' . $per_page; $data = array(); if ( ( ! $user = get_user_by( 'email', $email_address ) ) || ! $user->ID || ! $rows = cerber_get_log( null, array( 'id' => $user->ID ), null, $limit ) ) { $done = true; if ( $page == 1 ) { // Nothing was logged at all $data[] = array( 'name' => 'Events', 'value' => 'None logged' ); } } else { $done = false; // There are rows to be exported $labels = cerber_get_labels( 'activity' ); foreach ( $rows as $row ) { //$value = 'IP: ' . $row->ip . ' | ' . $labels[ $row->activity ]; $value = array( 'IP_ADDRESS' => $row->ip, 'EVENT' => $labels[ $row->activity ] ); if ( $row->user_login ) { $value['USERNAME'] = $row->user_login; } $value = json_encode( $value, JSON_UNESCAPED_UNICODE ); // Format is defined by WordPress $data[] = array( 'name' => cerber_date( $row->stamp ), // First column 'value' => $value // Second column ); } } return crb_pdata_formater( $data, 'cerber-activity', 'Activity Log', $done ); } function crb_pdata_exporter_trf( $email_address, $page = 1 ) { $per_page = 500; // Rows per step (SQL query) $limit = ( $per_page * ( absint( $page ) - 1 ) ) . ',' . $per_page; $data = array(); if ( ( ! $user = get_user_by( 'email', $email_address ) ) || ! $user->ID || ! $rows = cerber_db_get_results( 'SELECT ip, uri, stamp, request_fields, request_details FROM ' . CERBER_TRAF_TABLE . ' WHERE user_id = ' . $user->ID . ' LIMIT ' . $limit, MYSQL_FETCH_OBJECT ) ) { $done = true; if ( $page == 1 ) { // Nothing was logged at all $data[] = array( 'name' => 'Events', 'value' => 'None logged' ); } } else { $done = false; // There are rows to be exported $what = crb_get_settings( 'pdata_trf' ); foreach ( $rows as $row ) { $value = array( 'IP_ADDRESS' => $row->ip ); if ( isset( $what[1] ) ) { $value['URL'] = $row->uri; } if ( isset( $what[2] ) ) { if ( $row->request_fields ) { $uns = unserialize( $row->request_fields ); if ( ! empty( $uns[1] ) ) { $value['FORM_FIEDLS'] = $uns[1]; } } } if ( isset( $what[3] ) ) { if ( $row->request_details ) { $uns = unserialize( $row->request_details ); if ( ! empty( $uns[8] ) ) { $value['COOKIES'] = $uns[8]; } } } $value = json_encode( $value, JSON_UNESCAPED_UNICODE ); // Format is defined by WordPress $data[] = array( 'name' => cerber_date( $row->stamp ), // First column 'value' => $value // Second column ); } } return crb_pdata_formater( $data, 'cerber-traffic', 'Traffic Log', $done ); } function crb_pdata_formater( $data = array(), $exp_id = '', $label = '', $done = true ) { $export_items[] = array( 'group_id' => $exp_id, 'group_label' => $label, 'item_id' => $exp_id, 'data' => $data, ); return array( 'data' => $export_items, 'done' => $done, ); } if ( crb_get_settings( 'pdata_export' ) ) { add_filter( 'wp_privacy_personal_data_exporters', 'crb_pdata_register_exporters' ); } function crb_pdata_register_exporters( $exporters ) { if ( crb_get_settings( 'pdata_act' ) ) { $exporters['cerber-security-act'] = array( 'exporter_friendly_name' => 'WP Cerber Activity', 'callback' => 'crb_pdata_exporter_act', ); } if ( crb_get_settings( 'pdata_trf' ) ) { $exporters['cerber-security-trf'] = array( 'exporter_friendly_name' => 'WP Cerber Traffic', 'callback' => 'crb_pdata_exporter_trf', ); } return $exporters; } // Personal data erasers ---------------------------------------- function crb_pdata_eraser( $email_address, $page = 1 ) { $removed = false; $retained = false; $done = true; $msg = array(); if ( is_super_admin() && ( $user = get_user_by( 'email', $email_address ) ) && $user->ID ) { cerber_db_query( 'DELETE FROM ' . CERBER_LOG_TABLE . ' WHERE user_id = ' . $user->ID ); cerber_db_query( 'DELETE FROM ' . CERBER_TRAF_TABLE . ' WHERE user_id = ' . $user->ID ); if ( ( $reg = get_user_meta( $user->ID, '_crb_reg_', true ) ) && ( empty( $reg['user'] ) || $reg['user'] == $user->ID ) ) { delete_user_meta( $user->ID, '_crb_reg_' ); } if ( crb_get_settings( 'pdata_sessions' ) ) { update_user_meta( $user->ID , 'session_tokens', array() ); } $removed = true; // Check if removing is OK if ( cerber_get_log( null, array( 'id' => $user->ID ), null, 1 ) || cerber_db_get_var( 'SELECT user_id FROM ' . CERBER_TRAF_TABLE . ' WHERE user_id = ' . $user->ID . ' LIMIT 1' ) ) { $removed = false; $retained = true; $done = false; if ( $page >= 3 ) { // We failed after three attempts $msg[] = 'WP Cerber is unable to delete rows in its log tables due to a database error. Check the server error log.'; $done = true; } } } return array( 'items_removed' => $removed, 'items_retained' => $retained, 'messages' => $msg, 'done' => $done, ); } if ( crb_get_settings( 'pdata_erase' ) ) { add_filter( 'wp_privacy_personal_data_erasers', 'crb_pdata_register_eraser' ); } function crb_pdata_register_eraser( $erasers ) { $erasers['cerber-security-erase'] = array( 'eraser_friendly_name' => __( 'WP Cerber Personal Data Eraser' ), 'callback' => 'crb_pdata_eraser', ); return $erasers; } class CRB_Sessions_Table extends WP_List_Table { private $geo; public function __construct() { parent::__construct( array( 'singular' => 'Session', 'plural' => 'Sessions', 'ajax' => false, 'screen' => 'cerber_user_sessions' // Without this it does not work ) ); $this->geo = lab_lab(); } // Columns definition function get_columns() { return array( 'cb' => '', //Render a checkbox instead of text 'ses_user' => __( 'User', 'wp-cerber' ), //'ses_role' => __( 'Role', 'wp-cerber' ), 'ses_started' => __( 'Created', 'wp-cerber' ), 'ses_expires' => __( 'Expires', 'wp-cerber' ), 'ses_ip' => '
' . __( 'IP Address', 'wp-cerber' ), 'ses_host' => __( 'Host Info', 'wp-cerber' ), 'ses_action' => __( 'Action', 'wp-cerber' ), ); } // Sortable columns function get_sortable_columns() { return array( 'ses_user' => array( 'user_id', false ), // true means dataset is already sorted by ASC 'ses_started' => array( 'started', false ), 'ses_expires' => array( 'expires', false ), 'ses_ip' => array( 'ip', false ), ); } // Bulk actions function get_bulk_actions() { return array( 'bulk_session_terminate' => __( 'Terminate session', 'wp-cerber' ), 'bulk_block_user' => __( 'Block user', 'wp-cerber' ), ); } // Retrieve data from the DB function prepare_items() { global $wpdb; // These quires show the same perfomance //if ( cerber_db_get_var( 'SELECT user_id FROM ' . cerber_get_db_prefix() . CERBER_USS_TABLE . ' WHERE expires < ' . time() . ' LIMIT 1' ) ) { $min = cerber_db_get_var( 'SELECT MIN(expires) FROM ' . cerber_get_db_prefix() . CERBER_USS_TABLE ); if ( ! $min || $min < time() ) { cerber_sync_sessions(); // full sync if there are expired sessions } else { cerber_sync_sessions( false ); // full sync if table is empty } $where = array(); $total_items = 0; $get = crb_get_query_params(); // Sorting $orderby = crb_array_get( $get, 'orderby', 'started', '\w+' ); $order = crb_array_get( $get, 'order', 'DESC', '\w+' ); $orderby = sanitize_sql_orderby( $orderby . ' ' . $order ); // !works only with fields, not tables references! $orderby = ' ORDER BY ' . $orderby . ' '; // Pagination, part 1, SQL $per_page = crb_admin_get_per_page(); $current_page = $this->get_pagenum(); if ( $current_page > 1 ) { $offset = ( $current_page - 1 ) * $per_page; $limit = ' LIMIT ' . $offset . ',' . $per_page; } else { $limit = 'LIMIT ' . $per_page; } // Search if ( $term = cerber_get_get( 's' ) ) { $term = stripslashes( $term ); $s = '"%' . cerber_real_escape( $term ) . '%"'; if ( preg_match( '/[^A-Z\d\-\/\.\:]/i', $term ) ) { // Mixing columns with different collations for non-latin symbols generates MySQL error $where[] = ''; } else { $where[] = ''; } } if ( $user_id = crb_array_get( $get, 'filter_user', 0, '\d+' ) ) { $where[] = 'user_id = ' . $user_id; } $where = ( ! empty( $where ) ) ? ' WHERE ' . implode( ' AND ', $where ) : ''; // Retrieving data $query = 'SELECT SQL_CALC_FOUND_ROWS * FROM ' . cerber_get_db_prefix() . CERBER_USS_TABLE . ' ses JOIN ' . $wpdb->users . ' us ON (ses.user_id = us.ID) ' . $where . $orderby . $limit; if ( $this->items = cerber_db_get_results( $query ) ) { $total_items = cerber_db_get_var( 'SELECT FOUND_ROWS()' ); } if ( ! empty( $term ) ) { echo '
' . __( 'Search results for:', 'wp-cerber' ) . ' “' . htmlspecialchars( $term ) . '”
'; } // Pagination, part 2 $this->set_pagination_args( array( 'total_items' => $total_items, 'per_page' => $per_page, 'total_pages' => ceil( $total_items / $per_page ) ) ); } public function single_row( $item ) { //$item['user_data'] = get_userdata( $item['user_id'] ); parent::single_row( $item ); } function column_cb( $item ) { if ( ! crb_admin_is_current_session( $item['wp_session_token'] ) ) { return ''; } return ''; } /** * @param array $item // not object! * @param string $column_name * * @return string */ function column_default( $item, $column_name ) { global $crb_ajax_loader; //return $item[ $column_name ]; // raw output as is switch ( $column_name ) { case 'ses_user': $label = ''; $links = ''; if ( ! nexus_is_valid_request() ) { $links = $this->row_actions( array( '' . __( 'Profile', 'wp-cerber' ) . '', ) ); $label = ( crb_admin_is_current_session( $item['wp_session_token'] ) ) ? __( 'You', 'wp-cerber' ) : ''; } return crb_admin_get_user_cell( $item['user_id'], cerber_admin_link( 'sessions' ), $links, $label ); break; case 'ses_started': $logins = cerber_activity_link( array( 5 ) ) . '&filter_user=' . $item['user_id']; $set = array( '' . __( 'All Logins', 'wp-cerber' ) . '', '' . __( 'User Activity', 'wp-cerber' ) . '' ); $url = ''; // TODO: make it via AJAX per user row with a click "Details" if ( $item['session_id'] ) { /*$log = cerber_db_get_row( 'SELECT * FROM ' . CERBER_LOG_TABLE . ' WHERE session_id = "' . $item['session_id'] . '"' ); if ( $log ) { $det = explode( '|', $log['details'] ); $url = $det[4]; }*/ } return '' . cerber_date( $item['started'] ) . '' . $this->row_actions( $set ); break; case 'ses_expires': return cerber_date( $item['expires'] ); break; case 'ses_ip': $set = array( '' . __( 'Activity', 'wp-cerber' ) . '', '' . __( 'Traffic', 'wp-cerber' ) . '' ); return crb_admin_ip_cell( $item['ip'], '', $this->row_actions( $set ) ); break; case 'ses_host': $ip_id = cerber_get_id_ip( $item['ip'] ); $ip_info = cerber_get_ip_info( $item['ip'], true ); if ( ! $hostname = crb_array_get( $ip_info, 'hostname_html' ) ) { $hostname = '' . "\n"; } $country = ( $this->geo ) ? '

' . crb_country_html( $item['country'], $item['ip'] ) . '

' : ''; return $hostname . $country; break; case 'ses_action': if ( crb_admin_is_current_session( $item['wp_session_token'] ) ) { return ''; } $href = wp_nonce_url( cerber_admin_link( 'sessions' ) . '&cerber_admin_do=terminate_session&id=' . $item['wp_session_token'] . '&user_id=' . $item['user_id'], 'control', 'cerber_nonce' ); return crb_confirmation_link( $href, __( 'Terminate', 'wp-cerber' ) ); break; } return ''; } function no_items() { if ( ! empty( $_GET['s'] ) ) { parent::no_items(); } else { echo 'No user sessions found.'; } } }