$user->user_login, 'CurrentUserID' => $user->ID, 'CurrentUserRoles' => $user_roles, ), true ); } } return; // Return. } $user = get_user_by( 'id', $user_id ); // bail early if we did not get a user object. if ( ! is_a( $user, '\WP_User' ) ) { return; } $user_login = $user->data->user_login; $user_roles = User_Helper::get_user_roles( $user ); $alert_data = array( 'Username' => $user_login, 'CurrentUserID' => $user_id, 'CurrentUserRoles' => $user_roles, 'LoginPageURL' => WP_Helper::try_to_get_http_referrer(), ); if ( class_exists( '\WSAL\Helpers\User_Sessions_Helper' ) ) { $alert_data['SessionID'] = User_Sessions_Helper::hash_token( $token ); } self::$login_queue['login'] = $alert_data; } /** * Event Logout. * * @since 4.5.0 */ public static function event_logout() { if ( self::$current_user->ID ) { // get the list of excluded users. $excluded_users = Settings_Helper::get_excluded_monitoring_users(); $excluded_user_ids = array(); // convert excluded usernames into IDs. if ( ! empty( $excluded_users ) && is_array( $excluded_users ) ) { foreach ( $excluded_users as $excluded_user ) { $user = \get_user_by( 'login', $excluded_user ); if ( $user && is_a( $user, '\WP_User' ) ) { $excluded_user_ids[] = $user->ID; } } } // bail early if this user is in the excluded ids list. if ( in_array( self::$current_user->ID, $excluded_user_ids, true ) ) { return; } $alert_data = array( 'CurrentUserID' => self::$current_user->ID, 'CurrentUserRoles' => User_Helper::get_user_roles( self::$current_user ), 'LoginPageURL' => WP_Helper::try_to_get_http_referrer(), ); Alert_Manager::trigger_event( 1001, $alert_data, true ); } } /** * Login failure limit count. * * @return int * * @since 4.5.0 */ // protected static function get_login_failure_log_limit() { // return Settings_Helper::get_option_value( 'log-failed-login-limit', 10 ); // } /** * Non-existing Login failure limit count. * * @return int * * @since 4.5.0 */ protected static function get_visitor_login_failure_log_limit() { return intval( Settings_Helper::get_option_value( 'log-visitor-failed-login-limit', 10 ) ); } /** * Expiration of the transient saved in the WP database. * * @return integer Time until expiration in seconds from now * * @since 4.5.0 */ protected static function get_login_failure_expiration() { return 12 * 60 * 60; } /** * Check failure limit. * * @param string $ip - IP address. * @param integer $site_id - Blog ID. * @param WP_User $user - User object. * * @return boolean - Passed limit true|false. * * @since 4.5.0 */ // protected static function is_past_login_failure_limit( $ip, $site_id, $user ) { // if ( $user ) { // if ( -1 === (int) self::get_login_failure_log_limit() ) { // return false; // } else { // $data_known = WP_Helper::get_transient( self::TRANSIENT_FAILEDLOGINS ); // return ( false !== $data_known ) && isset( $data_known[ $site_id . ':' . $user->ID . ':' . $ip ] ) && ( $data_known[ $site_id . ':' . $user->ID . ':' . $ip ] >= self::get_login_failure_log_limit() ); // } // } elseif ( -1 === (int) self::get_visitor_login_failure_log_limit() ) { // return false; // } else { // $data_unknown = WP_Helper::get_transient( self::TRANSIENT_FAILEDLOGINS_UNKNOWN ); // return ( false !== $data_unknown ) && isset( $data_unknown[ $site_id . ':' . $ip ] ) && ( $data_unknown[ $site_id . ':' . $ip ] >= self::get_visitor_login_failure_log_limit() ); // } // } /** * Increment failure limit. * * @param string $ip - IP address. * @param integer $site_id - Blog ID. * @param WP_User $user - User object. * * @since 4.5.0 */ protected static function increment_login_failure( $ip, $site_id, $user ) { if ( $user ) { $data_known = WP_Helper::get_transient( self::TRANSIENT_FAILEDLOGINS ); $last_inc = WP_Helper::get_transient( self::TRANSIENT_FAILEDLOGINS_LAST ); // Check if this has already been logged and counted. if ( $last_inc && $last_inc === $user->ID ) { WP_Helper::set_transient( self::TRANSIENT_FAILEDLOGINS_NO_INCREMENT, $user->ID, 10 ); return; } if ( ! $data_known ) { $data_known = array(); } if ( ! isset( $data_known[ $site_id . ':' . $user->ID . ':' . $ip ] ) ) { $data_known[ $site_id . ':' . $user->ID . ':' . $ip ] = 1; } ++$data_known[ $site_id . ':' . $user->ID . ':' . $ip ]; WP_Helper::set_transient( self::TRANSIENT_FAILEDLOGINS, $data_known, self::get_login_failure_expiration() ); WP_Helper::set_transient( self::TRANSIENT_FAILEDLOGINS_LAST, $user->ID, 10 ); } else { $data_unknown = WP_Helper::get_transient( self::TRANSIENT_FAILEDLOGINS_UNKNOWN ); if ( ! $data_unknown ) { $data_unknown = array(); } if ( ! isset( $data_unknown[ $site_id . ':' . $ip ] ) ) { $data_unknown[ $site_id . ':' . $ip ] = 1; } ++$data_unknown[ $site_id . ':' . $ip ]; WP_Helper::set_transient( self::TRANSIENT_FAILEDLOGINS_UNKNOWN, $data_unknown, self::get_login_failure_expiration() ); } } /** * Event Login failure. * * @param string $username Username. * @param \WP_Error|null $error - More details about the error. * * @since 4.5.0 */ public static function event_login_failure( $username, $error = null ) { $ip = Settings_Helper::get_main_client_ip(); // Filter $_POST global array for security. $post_array = filter_input_array( INPUT_POST ); $username = isset( $post_array['log'] ) ? \sanitize_text_field( \wp_unslash( $post_array['log'] ) ) : $username; $username = \sanitize_user( $username ); $new_alert_code = 1003; $user = \get_user_by( 'login', $username ); // If we still don't have the user, lets look for them using there email address. if ( empty( $user ) ) { $user = \get_user_by( 'email', $username ); } $site_id = ( function_exists( 'get_current_blog_id' ) ? get_current_blog_id() : 0 ); if ( $user ) { $new_alert_code = 1002; $user_roles = User_Helper::get_user_roles( $user ); } // Check if the alert is disabled from the "Enable/Disable Alerts" section. if ( ! Alert_Manager::is_enabled( $new_alert_code ) ) { return; } $error_message = ''; if ( \is_wp_error( $error ) ) { $error_message = $error->get_error_message(); } if ( 1002 === $new_alert_code ) { if ( ! Alert_Manager::check_enable_user_roles( $username, $user_roles ) ) { return; } if ( Alert_Manager::will_or_has_triggered( 1004 ) ) { // Skip if 1004 (session block) is already in place. return; } // Create a new record exists user. Alert_Manager::trigger_event_if( $new_alert_code, array( 'Attempts' => 1, 'Username' => $username, 'CurrentUserID' => $user->ID, 'LogFileText' => '', 'CurrentUserRoles' => $user_roles, 'error_message' => ( ! empty( $error_message ) ) ? $error_message : null, 'LoginPageURL' => WP_Helper::try_to_get_http_referrer(), ), /** * Skip if 1004 (session block) is already in place. * * @return bool */ function () { return ! ( Alert_Manager::will_or_has_triggered( 1004 ) || Alert_Manager::has_triggered( 1002 ) ); } ); } else { // Log an alert for a login attempt with unknown username. Alert_Manager::trigger_event( $new_alert_code, array( 'Attempts' => 1, 'Users' => $username, 'LogFileText' => '', 'ClientIP' => $ip, 'error_message' => ( ! empty( $error_message ) ) ? $error_message : null, 'LoginPageURL' => WP_Helper::try_to_get_http_referrer(), ) ); } } /** * Event changed password. * * @param WP_User $user - User object. * @param string $new_pass - New Password. * * @since 4.5.0 */ public static function event_password_reset( $user, $new_pass ) { if ( ! empty( $user ) ) { $user_roles = User_Helper::get_user_roles( $user ); Alert_Manager::trigger_event( 4003, array( 'Username' => $user->user_login, 'CurrentUserID' => $user->ID, 'CurrentUserRoles' => $user_roles, ), true ); } } /** * User Switched. * * Current user switched to another user event. * * @param int $new_user_id - New user id. * @param int $old_user_id - Old user id. * * @since 4.5.0 */ public static function user_switched_event( $new_user_id, $old_user_id ) { $target_user = \get_user_by( 'ID', $new_user_id ); $target_user_roles = User_Helper::get_user_roles( $target_user ); $target_user_roles = implode( ', ', $target_user_roles ); $old_user = \get_user_by( 'ID', $old_user_id ); $old_user_roles = User_Helper::get_user_roles( $old_user ); Alert_Manager::trigger_event( 1008, array( 'TargetUserName' => $target_user->user_login, 'TargetUserRole' => $target_user_roles, 'Username' => $old_user->user_login, 'CurrentUserID' => $old_user->ID, 'CurrentUserRoles' => $old_user_roles, ) ); } /** * User has requested a password reset. * * @param object $errors Current WP_errors object. * @param object $user User making the request. * * @since 4.5.0 */ public static function event_user_requested_pw_reset( $errors, $user = null ) { // If we don't have the user, do nothing. if ( is_null( $user ) || ! isset( $user->roles ) ) { return; } $user_roles = User_Helper::get_user_roles( $user ); Alert_Manager::trigger_event( 1010, array( 'Username' => $user->user_login, 'CurrentUserRoles' => $user_roles, // Current user ID must be set explicitly as the user is not logged in when this happens. 'CurrentUserID' => $user->ID, ), true ); } /** * Checks queue with the logged events and executes them based on the login / logout logic * This is for 2fa plugins - after successful login, a login event is captured, but after that these plugins logout the user so they can implement proper 2fa check - so if that is the sequence - don't log events and wait. * * @return void * * @since 5.3.0 */ public static function shutdown_empty_queue() { if ( ! empty( self::$login_queue ) && isset( self::$login_queue['login'] ) ) { if ( ! isset( self::$login_queue['logout'] ) ) { Alert_Manager::trigger_event_if( 1000, self::$login_queue['login'], /** * Don't fire if the user is changing their password via admin profile page. * * @return bool */ function () { return ! ( Alert_Manager::will_or_has_triggered( 4003 ) || Alert_Manager::has_triggered( 1000 ) || Alert_Manager::will_or_has_triggered( 1005 ) ); } ); } } } } }