From d93bad3cd3bd3178cd3318a5d998643291b5207a Mon Sep 17 00:00:00 2001 From: John Blackbourn Date: Thu, 13 Nov 2014 15:20:42 +0000 Subject: [PATCH] Introduce a button on the user profile screen which clears all other sessions, and on the user editing screen which clears all sessions. Only appears when there are applicable sessions which can be cleared. See #30264. Props jorbin, ocean90, johnbillion git-svn-id: https://develop.svn.wordpress.org/trunk@30333 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/admin-ajax.php | 2 +- src/wp-admin/css/forms.css | 5 +++ src/wp-admin/includes/ajax-actions.php | 51 ++++++++++++++++++++++++++ src/wp-admin/js/user-profile.js | 27 +++++++++++++- src/wp-admin/user-edit.php | 35 ++++++++++++++++++ src/wp-includes/session.php | 17 +++++++-- 6 files changed, 131 insertions(+), 6 deletions(-) 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 {