Ticket #34281: 34281.2.diff
File 34281.2.diff, 17.7 KB (added by , 10 years ago) |
---|
-
src/wp-admin/admin-ajax.php
62 62 'send-attachment-to-editor', 'save-attachment-order', 'heartbeat', 'get-revision-diffs', 63 63 'save-user-color-scheme', 'update-widget', 'query-themes', 'parse-embed', 'set-attachment-thumbnail', 64 64 'parse-media-shortcode', 'destroy-sessions', 'install-plugin', 'update-plugin', 'press-this-save-post', 65 'press-this-add-category', 'crop-image', 'generate-password', 65 'press-this-add-category', 'crop-image', 'generate-password', 'send-password-reset', 66 66 ); 67 67 68 68 // Deprecated -
src/wp-admin/includes/ajax-actions.php
3243 3243 function wp_ajax_generate_password() { 3244 3244 wp_send_json_success( wp_generate_password( 24 ) ); 3245 3245 } 3246 3247 /** 3248 * Ajax handler sends a password reset link. 3249 * 3250 * @since 4.4.0 3251 */ 3252 function wp_ajax_send_password_reset() { 3253 3254 // Validate the nonce for this action. 3255 $user_id = isset( $_POST['user_id'] ) ? (int) $_POST['user_id'] : 0; 3256 check_ajax_referer( 'reset-password-for-' . $user_id, 'nonce' ); 3257 3258 // Verify user capabilities. 3259 if ( ! current_user_can( 'edit_user', $user_id ) ) { 3260 wp_send_json_error( __( 'Cannot send password reset, permission denied.' ) ); 3261 } 3262 3263 // Send the password reset. 3264 $user = get_userdata( $user_id ); 3265 3266 // Pass the username via $_POST. 3267 $_POST['user_login'] = esc_attr( $user->user_login ); 3268 3269 $results = retrieve_password(); 3270 3271 if ( true === $results ) { 3272 wp_send_json_success( 3273 /* translators: 1: User's display name. */ 3274 sprintf( __( 'A password reset link was emailed to %s.' ), $user->display_name ) 3275 ); 3276 } else { 3277 wp_send_json_error( $results ); 3278 } 3279 } -
src/wp-admin/includes/class-wp-users-list-table.php
235 235 } else { 236 236 if ( current_user_can( 'delete_users' ) ) 237 237 $actions['delete'] = __( 'Delete' ); 238 238 239 } 239 240 241 // Add a password reset link to the bulk actions dropdown. 242 if ( current_user_can( 'edit_users' ) ) { 243 $actions['resetpassword'] = __( 'Send password reset' ); 244 } 245 240 246 return $actions; 241 247 } 242 248 … … 403 409 $actions['delete'] = "<a class='submitdelete' href='" . wp_nonce_url( "users.php?action=delete&user=$user_object->ID", 'bulk-users' ) . "'>" . __( 'Delete' ) . "</a>"; 404 410 if ( is_multisite() && get_current_user_id() != $user_object->ID && current_user_can( 'remove_user', $user_object->ID ) ) 405 411 $actions['remove'] = "<a class='submitdelete' href='" . wp_nonce_url( $url."action=remove&user=$user_object->ID", 'bulk-users' ) . "'>" . __( 'Remove' ) . "</a>"; 412 // Add a link to send the user a reset password link by email. 413 if ( get_current_user_id() != $user_object->ID && current_user_can( 'edit_user', $user_object->ID ) ) 414 $actions['resetpassword'] = "<a class='resetpassword' href='" . wp_nonce_url( "users.php?action=resetpassword&users=$user_object->ID", 'bulk-users' ) . "'>" . __( 'Send password reset' ) . "</a>"; 406 415 416 407 417 /** 408 418 * Filter the action links displayed under each user in the Users list table. 409 419 * -
src/wp-admin/js/user-profile.js
152 152 }); 153 153 } 154 154 155 /** 156 * Handle the password reset button. Sets up an ajax callback to trigger sending 157 * a password reset email. 158 */ 159 function bindPasswordRestLink() { 160 $( '#generate-reset-link' ).on( 'click', function() { 161 var $this = $(this), 162 data = { 163 'user_id': userProfileL10n.user_id, // The user to send a reset to. 164 'nonce': userProfileL10n.nonce // Nonce to validate the action. 165 }, 166 // Send the reset request. 167 resetAction = wp.ajax.post( 'send-password-reset', data ); 168 169 // Handle reset success. 170 resetAction.done( function( response ) { 171 addInlineNotice( $this, true, response ); 172 } ); 173 174 // Handle reset failure. 175 resetAction.fail( function( response ) { 176 addInlineNotice( $this, false, response ); 177 } ); 178 179 }); 180 181 } 182 183 /** 184 * Helper function to insert an inline notice of success or failure. 185 * 186 * @param {jQuery Object} $this The button element: the message will be inserted 187 * above this button 188 * @param {bool} success Whether the message is a success message. 189 * @param {string} message The message to insert. 190 */ 191 function addInlineNotice( $this, success, message ) { 192 var resultDiv = $( '<div />' ); 193 194 // Set up the notice div. 195 resultDiv.addClass( 'notice inline' ); 196 197 // Add a class indicating success or failure. 198 resultDiv.addClass( 'notice-' + ( success ? 'success' : 'error' ) ); 199 200 // Add the message, using text for security, wrapping in a p tag. 201 resultDiv.text( message ).wrapInner( '<p />' ); 202 203 // Disable the button when the callback has succeeded. 204 $this.prop( 'disabled', success ); 205 206 // Remove any previous notices. 207 $this.siblings( '.notice' ).remove(); 208 209 // Insert the notice. 210 $this.before( resultDiv ); 211 } 212 155 213 function bindPasswordForm() { 156 214 var $passwordWrapper, 157 215 $generateButton, … … 380 438 }); 381 439 382 440 bindPasswordForm(); 441 bindPasswordRestLink(); 383 442 }); 384 443 385 444 $( '#destroy-sessions' ).on( 'click', function( e ) { -
src/wp-admin/user-edit.php
491 491 </td> 492 492 </tr> 493 493 <?php endif; ?> 494 <?php 495 // Allow admins to send reset password link 496 if ( ! IS_PROFILE_PAGE ) : 497 ?> 498 <tr class="user-sessions-wrap hide-if-no-js"> 499 <th><?php _e( 'Password Reset' ); ?></th> 500 <td> 501 <div class="generate-reset-link"> 502 <button type="button" class="button button-secondary" id="generate-reset-link"> 503 <?php _e( 'Send Reset Link' ); ?> 504 </button> 505 </div> 506 <p class="description"> 507 <?php 508 /* translators: 1: User's display name. */ 509 printf( __( 'Send %s a link to reset their password. This will not change their password, nor will it force a change.' ), esc_html( $profileuser->display_name ) ); 510 ?> 511 </p> 512 </td> 513 </tr> 514 <?php endif; ?> 494 515 495 516 <?php 496 517 if ( IS_PROFILE_PAGE && count( $sessions->get_all() ) === 1 ) : ?> -
src/wp-admin/users.php
191 191 wp_redirect($redirect); 192 192 exit(); 193 193 194 case 'resetpassword': 195 check_admin_referer('bulk-users'); 196 if ( ! current_user_can( 'edit_users' ) ) { 197 $errors = new WP_Error( 'edit_users', __( 'You can’t edit users.' ) ); 198 } 199 if ( empty( $_REQUEST['users'] ) ) { 200 wp_redirect( $redirect ); 201 exit(); 202 } 203 $userids = array_map( 'intval', (array) $_REQUEST['users'] ); 204 205 $reset_count = 0; 206 207 foreach ( $userids as $id ) { 208 if ( ! current_user_can( 'edit_user', $id ) ) 209 wp_die(__( 'You can’t edit that user.' ) ); 210 211 if ( $id == $current_user->ID ) { 212 $update = 'err_admin_reset'; 213 continue; 214 } 215 216 // Send the password reset. 217 $user = get_userdata( $id ); 218 219 // Pass the username via $_POST. 220 $_POST['user_login'] = esc_attr( $user->user_login ); 221 222 if ( retrieve_password() ) { 223 ++$reset_count; 224 } 225 226 } 227 228 $redirect = add_query_arg( 229 array( 230 'reset_count' => $reset_count, 231 'update' => 'resetpassword', 232 ), $redirect 233 ); 234 wp_redirect( $redirect ); 235 exit(); 236 237 194 238 case 'delete': 195 239 if ( is_multisite() ) 196 240 wp_die( __('User deletion is not allowed from this screen.') ); … … 428 472 $messages[] = '<div id="message" class="updated notice is-dismissible"><p>' . __( 'New user created.' ) . '</p></div>'; 429 473 } 430 474 break; 475 case 'resetpassword': 476 $reset_count = isset( $_GET['reset_count'] ) ? (int) $_GET['reset_count'] : 0; 477 if ( 1 === $reset_count ) { 478 $message = __( 'Password reset link sent.' ); 479 } else { 480 $message = sprintf( __( 'Password reset links sent to %s users.' ), $reset_count ); 481 } 482 $messages[] = '<div id="message" class="updated notice is-dismissible"><p>' . $message . '</p></div>'; 483 break; 431 484 case 'promote': 432 485 $messages[] = '<div id="message" class="updated notice is-dismissible"><p>' . __('Changed roles.') . '</p></div>'; 433 486 break; … … 459 512 </ul> 460 513 </div> 461 514 <?php endif; 462 463 515 if ( ! empty($messages) ) { 464 516 foreach ( $messages as $msg ) 465 517 echo $msg; -
src/wp-includes/functions.php
5092 5092 // Strip timezone information 5093 5093 return preg_replace( '/(?:Z|[+-]\d{2}(?::\d{2})?)$/', '', $formatted ); 5094 5094 } 5095 5096 /** 5097 * Handles sending password retrieval email to user. 5098 * 5099 * @global wpdb $wpdb WordPress database abstraction object. 5100 * @global PasswordHash $wp_hasher Portable PHP password hashing framework. 5101 * 5102 * @return bool|WP_Error True: when finish. WP_Error on error 5103 */ 5104 function retrieve_password() { 5105 global $wpdb, $wp_hasher; 5106 5107 $errors = new WP_Error(); 5108 5109 if ( empty( $_POST['user_login'] ) ) { 5110 $errors->add('empty_username', __('<strong>ERROR</strong>: Enter a username or email address.')); 5111 } elseif ( strpos( $_POST['user_login'], '@' ) ) { 5112 $user_data = get_user_by( 'email', trim( $_POST['user_login'] ) ); 5113 if ( empty( $user_data ) ) 5114 $errors->add('invalid_email', __('<strong>ERROR</strong>: There is no user registered with that email address.')); 5115 } else { 5116 $login = trim($_POST['user_login']); 5117 $user_data = get_user_by('login', $login); 5118 } 5119 5120 /** 5121 * Fires before errors are returned from a password reset request. 5122 * 5123 * @since 2.1.0 5124 * @since 4.4.0 Added the `$errors` parameter. 5125 * 5126 * @param WP_Error $errors A WP_Error object containing any errors generated 5127 * by using invalid credentials. 5128 */ 5129 do_action( 'lostpassword_post', $errors ); 5130 5131 if ( $errors->get_error_code() ) 5132 return $errors; 5133 5134 if ( !$user_data ) { 5135 $errors->add('invalidcombo', __('<strong>ERROR</strong>: Invalid username or email.')); 5136 return $errors; 5137 } 5138 5139 // Redefining user_login ensures we return the right case in the email. 5140 $user_login = $user_data->user_login; 5141 $user_email = $user_data->user_email; 5142 $key = get_password_reset_key( $user_data ); 5143 5144 if ( is_wp_error( $key ) ) { 5145 return $key; 5146 } 5147 5148 $message = __('Someone requested that the password be reset for the following account:') . "\r\n\r\n"; 5149 $message .= network_home_url( '/' ) . "\r\n\r\n"; 5150 $message .= sprintf(__('Username: %s'), $user_login) . "\r\n\r\n"; 5151 $message .= __('If this was a mistake, just ignore this email and nothing will happen.') . "\r\n\r\n"; 5152 $message .= __('To reset your password, visit the following address:') . "\r\n\r\n"; 5153 $message .= '<' . network_site_url("wp-login.php?action=rp&key=$key&login=" . rawurlencode($user_login), 'login') . ">\r\n"; 5154 5155 if ( is_multisite() ) 5156 $blogname = $GLOBALS['current_site']->site_name; 5157 else 5158 /* 5159 * The blogname option is escaped with esc_html on the way into the database 5160 * in sanitize_option we want to reverse this for the plain text arena of emails. 5161 */ 5162 $blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES); 5163 5164 $title = sprintf( __('[%s] Password Reset'), $blogname ); 5165 5166 /** 5167 * Filter the subject of the password reset email. 5168 * 5169 * @since 2.8.0 5170 * @since 4.4.0 Added the `$user_login` and `$user_data` parameters. 5171 * 5172 * @param string $title Default email title. 5173 * @param string $user_login The username for the user. 5174 * @param WP_User $user_data WP_User object. 5175 */ 5176 $title = apply_filters( 'retrieve_password_title', $title, $user_login, $user_data ); 5177 5178 /** 5179 * Filter the message body of the password reset mail. 5180 * 5181 * @since 2.8.0 5182 * @since 4.1.0 Added `$user_login` and `$user_data` parameters. 5183 * 5184 * @param string $message Default mail message. 5185 * @param string $key The activation key. 5186 * @param string $user_login The username for the user. 5187 * @param WP_User $user_data WP_User object. 5188 */ 5189 $message = apply_filters( 'retrieve_password_message', $message, $key, $user_login, $user_data ); 5190 5191 if ( $message && !wp_mail( $user_email, wp_specialchars_decode( $title ), $message ) ) 5192 wp_die( __('The email could not be sent.') . "<br />\n" . __('Possible reason: your host may have disabled the mail() function.') ); 5193 5194 return true; 5195 } -
src/wp-includes/script-loader.php
382 382 'mismatch' => _x( 'Mismatch', 'password mismatch' ), 383 383 ) ); 384 384 385 $user_id = isset( $_GET['user_id'] ) ? (int) $_GET['user_id'] : 0; 385 386 $scripts->add( 'user-profile', "/wp-admin/js/user-profile$suffix.js", array( 'jquery', 'password-strength-meter', 'wp-util' ), false, 1 ); 386 387 did_action( 'init' ) && $scripts->localize( 'user-profile', 'userProfileL10n', array( 387 388 'warn' => __( 'Your new password has not been saved.' ), … … 390 391 'cancel' => __( 'Cancel' ), 391 392 'ariaShow' => esc_attr__( 'Show password' ), 392 393 'ariaHide' => esc_attr__( 'Hide password' ), 394 'user_id' => $user_id, 395 'nonce' => wp_create_nonce( 'reset-password-for-' . $user_id ), 393 396 ) ); 394 397 395 398 $scripts->add( 'language-chooser', "/wp-admin/js/language-chooser$suffix.js", array( 'jquery' ), false, 1 ); -
src/wp-login.php
267 267 <?php 268 268 } 269 269 270 /**271 * Handles sending password retrieval email to user.272 *273 * @global wpdb $wpdb WordPress database abstraction object.274 * @global PasswordHash $wp_hasher Portable PHP password hashing framework.275 *276 * @return bool|WP_Error True: when finish. WP_Error on error277 */278 function retrieve_password() {279 global $wpdb, $wp_hasher;280 281 $errors = new WP_Error();282 283 if ( empty( $_POST['user_login'] ) ) {284 $errors->add('empty_username', __('<strong>ERROR</strong>: Enter a username or email address.'));285 } elseif ( strpos( $_POST['user_login'], '@' ) ) {286 $user_data = get_user_by( 'email', trim( $_POST['user_login'] ) );287 if ( empty( $user_data ) )288 $errors->add('invalid_email', __('<strong>ERROR</strong>: There is no user registered with that email address.'));289 } else {290 $login = trim($_POST['user_login']);291 $user_data = get_user_by('login', $login);292 }293 294 /**295 * Fires before errors are returned from a password reset request.296 *297 * @since 2.1.0298 * @since 4.4.0 Added the `$errors` parameter.299 *300 * @param WP_Error $errors A WP_Error object containing any errors generated301 * by using invalid credentials.302 */303 do_action( 'lostpassword_post', $errors );304 305 if ( $errors->get_error_code() )306 return $errors;307 308 if ( !$user_data ) {309 $errors->add('invalidcombo', __('<strong>ERROR</strong>: Invalid username or email.'));310 return $errors;311 }312 313 // Redefining user_login ensures we return the right case in the email.314 $user_login = $user_data->user_login;315 $user_email = $user_data->user_email;316 $key = get_password_reset_key( $user_data );317 318 if ( is_wp_error( $key ) ) {319 return $key;320 }321 322 $message = __('Someone requested that the password be reset for the following account:') . "\r\n\r\n";323 $message .= network_home_url( '/' ) . "\r\n\r\n";324 $message .= sprintf(__('Username: %s'), $user_login) . "\r\n\r\n";325 $message .= __('If this was a mistake, just ignore this email and nothing will happen.') . "\r\n\r\n";326 $message .= __('To reset your password, visit the following address:') . "\r\n\r\n";327 $message .= '<' . network_site_url("wp-login.php?action=rp&key=$key&login=" . rawurlencode($user_login), 'login') . ">\r\n";328 329 if ( is_multisite() )330 $blogname = $GLOBALS['current_site']->site_name;331 else332 /*333 * The blogname option is escaped with esc_html on the way into the database334 * in sanitize_option we want to reverse this for the plain text arena of emails.335 */336 $blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);337 338 $title = sprintf( __('[%s] Password Reset'), $blogname );339 340 /**341 * Filter the subject of the password reset email.342 *343 * @since 2.8.0344 * @since 4.4.0 Added the `$user_login` and `$user_data` parameters.345 *346 * @param string $title Default email title.347 * @param string $user_login The username for the user.348 * @param WP_User $user_data WP_User object.349 */350 $title = apply_filters( 'retrieve_password_title', $title, $user_login, $user_data );351 352 /**353 * Filter the message body of the password reset mail.354 *355 * @since 2.8.0356 * @since 4.1.0 Added `$user_login` and `$user_data` parameters.357 *358 * @param string $message Default mail message.359 * @param string $key The activation key.360 * @param string $user_login The username for the user.361 * @param WP_User $user_data WP_User object.362 */363 $message = apply_filters( 'retrieve_password_message', $message, $key, $user_login, $user_data );364 365 if ( $message && !wp_mail( $user_email, wp_specialchars_decode( $title ), $message ) )366 wp_die( __('The email could not be sent.') . "<br />\n" . __('Possible reason: your host may have disabled the mail() function.') );367 368 return true;369 }370 371 270 // 372 271 // Main 373 272 //