Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make use of get_password_reset_key() in reset_password() method #23

Open
mathiasastrom opened this issue Apr 24, 2018 · 1 comment
Open

Comments

@mathiasastrom
Copy link

mathiasastrom commented Apr 24, 2018

Great plugin, saved me a great deal of pain.

Experienced buggy behaviour when I tried to reset the password through the WP REST api callback, the reset key was never updating and it was stuck in the same corrupt key. Much needed logic that was in your reset_password() method already exists in the core function: get_password_reset_key() - The function was added in WP 4.4 and should be safe to use I believe. (Depending on which WP versions you are supporting)

Feel free to use/test my modified method below:

/**
 * Endpoint for requesting a password reset link.
 * This is a slightly modified version of what WP core uses.
 *
 * @param object $request The request object that come in from WP Rest API.
 * @since 1.0
 */
public function reset_password( $request ) {
	$username = $request->get_param( 'username' );
	if ( ! $username ) {
		return array(
			'code' => 'jwt_auth_invalid_username',
			'message' => __( '<strong>Error:</strong> Username or email not specified.', 'simple-jwt-authentication' ),
			'data' => array(
				'status' => 403,
			),
		);
	} elseif ( strpos( $username, '@' ) ) {
		$user_data = get_user_by( 'email', trim( $username ) );
	} else {
		$user_data = get_user_by( 'login', trim( $username ) );
	}

	global $wpdb, $current_site;

	do_action( 'lostpassword_post' );
	if ( ! $user_data ) {
		return array(
			'code' => 'jwt_auth_invalid_username',
			'message' => __( '<strong>Error:</strong> Invalid username.', 'simple-jwt-authentication' ),
			'data' => array(
				'status' => 403,
			),
		);
	}

	// redefining user_login ensures we return the right case in the email
	$user_login = $user_data->user_login;
	$user_email = $user_data->user_email;

	$key = get_password_reset_key( $user_data );

	// Some simple error management
	if( is_wp_error( $key ) || !$key ){

		$default_err_response = array(
			'code' => 'jwt_auth_reset_password_not_allowed',
			'message' => __( '<strong>Error:</strong> Resetting password is not allowed.', 'simple-jwt-authentication' ),
			'data' => array(
				'status' => 403,
			)
		);

		// Check for "falsy" results, no WP_Error objects
		if( !is_wp_error( $key ) && !$key ){
			return $default_err_response;
		}

		// Get the error code
		$error_code = $key->get_error_code();

		// Lets check for some normal error messages you might recieve from get_password_reset_key() function
		if( $error_code === 'no_password_reset' ){
			// Check if resetting the password for the user is allowed
			return $default_err_response;
		}elseif( $error_code === 'no_password_key_update' ){
			// Failed to update the reset key to the database
			return array(
				'code' => 'jwt_auth_reset_password_no_password_key_update',
				'message' => __( '<strong>Error:</strong> Could not save password reset key to database.', 'simple-jwt-authentication' ),
				'data' => array(
					'status' => 403,
				)
			);
		}else{
			// Fallback error, maybe WP added an new error code that we do not support...
			return $default_err_response;
		}
	}

	$message = __( 'Someone requested that the password be reset for the following account:' ) . "\r\n\r\n";
	$message .= network_home_url( '/' ) . "\r\n\r\n";
	$message .= sprintf( __( 'Username: %s' ), $user_login ) . "\r\n\r\n";
	$message .= __( 'If this was a mistake, just ignore this email and nothing will happen.' ) . "\r\n\r\n";
	$message .= __( 'To reset your password, visit the following address:' ) . "\r\n\r\n";
	$message .= '<' . network_site_url( "wp-login.php?action=rp&key=$key&login=" . rawurlencode( $user_login ), 'login' ) . ">\r\n";

	if ( is_multisite() ) {
		$blogname = $GLOBALS['current_site']->site_name;
	} else {
		// The blogname option is escaped with esc_html on the way into the database in sanitize_option
		// we want to reverse this for the plain text arena of emails.
		$blogname = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
	}

	$title = sprintf( __( '[%s] Password Reset' ), $blogname );

	$title = apply_filters( 'retrieve_password_title', $title );
	$message = apply_filters( 'retrieve_password_message', $message, $key );

	if ( $message && ! wp_mail( $user_email, $title, $message ) ) {
		wp_die( __( 'The e-mail could not be sent.' ) . "<br />\n" . __( 'Possible reason: your host may have disabled the mail() function...' ) );
	}

	return array(
		'code' => 'jwt_auth_password_reset',
		'message' => __( '<strong>Success:</strong> an email for selecting a new password has been sent.', 'simple-jwt-authentication' ),
		'data' => array(
			'status' => 200,
		),
	);
}
@jonathan-dejong
Copy link
Owner

Hi Mathias,

Thanks for pointing this out! When I added the reset endpoint I just looked at what was in core at the time and how others had solved it and found that it worked but was a little bit buggy. I did not know about this new function!

I don't think compatibility is an issue since this plugin is aimed towards new development with WordPress (REST) :)

Would you mind turning your fix into a PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants