diff --git a/src/wp-admin/admin-ajax.php b/src/wp-admin/admin-ajax.php index 60f1778cd1..7e31623ffc 100644 --- a/src/wp-admin/admin-ajax.php +++ b/src/wp-admin/admin-ajax.php @@ -61,7 +61,7 @@ $core_actions_post = array( 'query-attachments', 'save-attachment', 'save-attachment-compat', 'send-link-to-editor', 'send-attachment-to-editor', 'save-attachment-order', 'heartbeat', 'get-revision-diffs', 'save-user-color-scheme', 'update-widget', 'query-themes', 'parse-embed', 'set-attachment-thumbnail', - 'parse-media-shortcode' + 'parse-media-shortcode', 'destroy-sessions' ); // Register core Ajax calls. diff --git a/src/wp-admin/css/forms.css b/src/wp-admin/css/forms.css index b80f98aaa2..250c31679a 100644 --- a/src/wp-admin/css/forms.css +++ b/src/wp-admin/css/forms.css @@ -611,6 +611,11 @@ table.form-table td .updated { font-size: 13px; } +table.form-table td .updated p { + font-size: 13px; + margin: 0.3em 0; +} + /*------------------------------------------------------------------------------ 18.0 - Users ------------------------------------------------------------------------------*/ diff --git a/src/wp-admin/includes/ajax-actions.php b/src/wp-admin/includes/ajax-actions.php index 5448f24c53..20fa265ee4 100644 --- a/src/wp-admin/includes/ajax-actions.php +++ b/src/wp-admin/includes/ajax-actions.php @@ -2770,3 +2770,54 @@ function wp_ajax_parse_media_shortcode() { 'body' => ob_get_clean() ) ); } + +/** + * AJAX handler for destroying multiple open sessions for a user. + * + * @since 4.1.0 + * + */ +function wp_ajax_destroy_sessions() { + + if ( empty( $_POST['user_id'] ) ) { + $user = new WP_Error(); + } else { + $user = new WP_User( absint( $_POST['user_id'] ) ); + + if ( ! $user->exists() ) { + $user = new WP_Error(); + } elseif ( ! current_user_can( 'edit_user', $user->ID ) ) { + $user = new WP_Error(); + } elseif ( ! check_ajax_referer( sprintf( 'destroy_sessions_%d', $user->ID ), false, false ) ) { + $user = new WP_Error(); + } + } + + if ( is_wp_error( $user ) ) { + wp_send_json_error( array( + 'message' => __( 'Could not log out user sessions. Please try again.' ), + ) ); + } + + if ( isset( $_POST['token'] ) ) { + $keep = wp_unslash( $_POST['token'] ); + } else { + $keep = null; + } + + $sessions = WP_Session_Tokens::get_instance( $user->ID ); + + if ( is_string( $keep ) ) { + $sessions->destroy_others( $keep ); + $message = __( 'You are now logged out everywhere else' ); + } else { + $sessions->destroy_all(); + /* translators: 1: User's display name. */ + $message = sprintf( __( '%s has been logged out' ), $user->display_name ); + } + + wp_send_json_success( array( + 'message' => $message + ) ); + +} diff --git a/src/wp-admin/js/user-profile.js b/src/wp-admin/js/user-profile.js index b107d98779..9586dbc1d3 100644 --- a/src/wp-admin/js/user-profile.js +++ b/src/wp-admin/js/user-profile.js @@ -1,4 +1,4 @@ -/* global ajaxurl, pwsL10n */ +/* global ajaxurl, pwsL10n, _wpSessionMangager */ (function($){ function check_pass_strength() { @@ -124,4 +124,29 @@ }); }); + $('#destroy-sessions').on('click',function(e){ + + var $this = $(this); + var data = { + action : 'destroy-sessions', + _ajax_nonce : _wpSessionMangager.nonce, + user_id : _wpSessionMangager.user_id, + token : $(this).data('token') + }; + + $.post( ajaxurl, data, function( response ) { + + if ( response.success ) { + $this.prop( 'disabled', true ); + $this.before( '

' + response.data.message + '

' ); + } else { + $this.before( '

' + response.data.message + '

' ); + } + + }, 'json' ); + + e.preventDefault(); + + }); + })(jQuery); diff --git a/src/wp-admin/user-edit.php b/src/wp-admin/user-edit.php index a2b7040515..d384d5425e 100644 --- a/src/wp-admin/user-edit.php +++ b/src/wp-admin/user-edit.php @@ -25,6 +25,15 @@ elseif ( ! get_userdata( $user_id ) ) wp_enqueue_script('user-profile'); +wp_localize_script( + 'user-profile', + '_wpSessionMangager', + array( + 'user_id' => $user_id, + 'nonce' => wp_create_nonce( sprintf( 'destroy_sessions_%d', $user_id ) ), + ) +); + $title = IS_PROFILE_PAGE ? __('Profile') : __('Edit User'); if ( current_user_can('edit_users') && !IS_PROFILE_PAGE ) $submenu_file = 'users.php'; @@ -187,6 +196,8 @@ $profileuser = get_user_to_edit($user_id); if ( !current_user_can('edit_user', $user_id) ) wp_die(__('You do not have permission to edit this user.')); +$sessions = WP_Session_Tokens::get_instance( $profileuser->ID ); + include(ABSPATH . 'wp-admin/admin-header.php'); ?> @@ -289,6 +300,7 @@ if ( !( IS_PROFILE_PAGE && !$user_can_edit ) ) : ?> */ do_action( 'personal_options', $profileuser ); ?> + + +get_all() ) > 1 ) ) { ?> + +   + +

+

+ +

+ + +get_all() ) > 0 ) ) { ?> + +   + +

+

+ display_name ); ?> +

+ + + + user_id ); $session['expiration'] = $expiration; + // IP address. + if ( !empty( $_SERVER['REMOTE_ADDR'] ) ) { + $session['ip'] = $_SERVER['REMOTE_ADDR']; + } + + // User-agent. + if ( ! empty( $_SERVER['HTTP_USER_AGENT'] ) ) { + $session['ua'] = wp_unslash( $_SERVER['HTTP_USER_AGENT'] ); + } + + // Timestamp + $session['login'] = time(); + $token = wp_generate_password( 43, false, false ); $this->update( $token, $session ); @@ -383,10 +396,6 @@ class WP_User_Meta_Session_Tokens extends WP_Session_Tokens { * @param array $sessions Sessions. */ protected function update_sessions( $sessions ) { - if ( ! has_filter( 'attach_session_information' ) ) { - $sessions = wp_list_pluck( $sessions, 'expiration' ); - } - if ( $sessions ) { update_user_meta( $this->user_id, 'session_tokens', $sessions ); } else {