PluginProbe
bbPress / 2.6.19
bbPress v2.6.19
2.6.19 2.6.18 2.6.17 trunk 2.0 2.0-beta-1 2.0-beta-2b 2.0-beta-3 2.0-beta-3b 2.0-rc-2 2.0-rc-3 2.0-rc-4 2.0-rc-5 2.0.1 2.0.2 2.0.3 2.1 2.1-beta-1 2.1-rc1 2.1-rc2 2.1-rc3 2.1-rc4 2.1.1 2.1.2 2.1.3 All 74 releases
← All changes | includes/admin/converters/PHPWind.php +119 -1 2.6.18 → 2.6.19 View file →
@@ -9,9 +9,9 @@
9 9
10 10 /**
11 11 * Implementation of PHPWind Forum converter.
12 12 *
13 - * @since 2.5.0 bbPress (r5142)
13 + * @since 2.5.0 bbPress (r5143)
14 14 *
15 15 * @link Codex Docs https://codex.bbpress.org/import-forums/phpwind
16 16 */
17 17 class PHPWind extends BBP_Converter_Base {
@@ -525,8 +525,126 @@
525 525 return hash_equals(
526 526 $pass_array['hash'],
527 527 md5( md5( $password ) . $pass_array['salt'] )
528 528 );
529 + }
530 +
531 + /**
532 + * Upgrade password metadata written by earlier PHPWind imports.
533 + *
534 + * Earlier imports stored PHPWind's random synchronization token instead of
535 + * its login hash and salt. New imports use the parent callback and serialized
536 + * metadata containing the login hash and salt.
537 + *
538 + * @param string $username WordPress user login.
539 + * @param string $password Unslashed password for PHPWind.
540 + * @param string|null $wp_password Optional slashed password for WordPress.
541 + */
542 + public function callback_pass( $username = '', $password = '', $wp_password = null ) {
543 + $user = get_user_by( 'login', $username );
544 +
545 + if ( ! empty( $user ) && '' === $user->user_pass ) {
546 + $stored_hash = get_user_meta( $user->ID, '_bbp_password', true );
547 +
548 + if ( is_string( $stored_hash ) && preg_match( '/^[a-f0-9]{32}$/i', $stored_hash ) ) {
549 + $serialized_pass = $this->get_source_password( $user, $stored_hash );
550 +
551 + if ( is_string( $serialized_pass ) && $this->authenticate_pass( $password, $serialized_pass ) ) {
552 + $this->upgrade_user_pass( $user->ID, is_null( $wp_password ) ? $password : $wp_password );
553 + }
554 +
555 + return;
556 + }
557 + }
558 +
559 + parent::callback_pass( $username, $password, $wp_password );
560 + }
561 +
562 + /**
563 + * Upgrade a PHPWind hash copied directly into wp_users by an old import.
564 + *
565 + * Those imports stored PHPWind's random synchronization token, not its login
566 + * hash. Match that token against the retained source row before retrieving
567 + * the login hash and salt from WindID.
568 + *
569 + * @param WP_User $user WordPress user.
570 + * @param string $password Unslashed password for PHPWind.
571 + * @param string|null $wp_password Optional slashed password for WordPress.
572 + */
573 + public function callback_user_pass( $user, $password, $wp_password = null ) {
574 + if ( ! ( $user instanceof WP_User ) || ! is_string( $password ) || ! preg_match( '/^[a-f0-9]{32}$/i', $user->user_pass ) ) {
575 + return;
576 + }
577 +
578 + $wp_password = is_null( $wp_password ) ? $password : $wp_password;
579 +
580 + // Do not replace a password that WordPress or a password plugin already
581 + // recognizes, regardless of the stored hash format.
582 + if ( wp_check_password( $wp_password, $user->user_pass, $user->ID ) ) {
583 + return;
584 + }
585 +
586 + $serialized_pass = $this->get_source_password( $user, $user->user_pass );
587 +
588 + if ( is_string( $serialized_pass ) && $this->authenticate_pass( $password, $serialized_pass ) ) {
589 + $this->upgrade_user_pass( $user->ID, $wp_password );
590 + }
591 + }
592 +
593 + /**
594 + * Retrieve login metadata for a token written by an earlier import.
595 + *
596 + * @param WP_User $user WordPress user.
597 + * @param string $stored_hash Random token stored by the earlier import.
598 + * @return string|bool Serialized password metadata, or false on failure.
599 + */
600 + private function get_source_password( $user, $stored_hash ) {
601 + $old_user_id = (int) get_user_meta( $user->ID, '_bbp_old_user_id', true );
602 + if ( $old_user_id < 1 || get_transient( 'bbp_phpwind_source_connection_failed' ) ) {
603 + return false;
604 + }
605 +
606 + // Block concurrent login attempts while the source connection or query is pending.
607 + // Keep the backoff when either fails, so an unavailable source cannot stall
608 + // every login attempt for an imported username.
609 + set_transient( 'bbp_phpwind_source_connection_failed', 1, 5 * MINUTE_IN_SECONDS );
610 +
611 + if ( ! $this->opdb->db_connect( false ) ) {
612 + return false;
613 + }
614 +
615 + $legacy_table = $this->opdb->prefix . 'user';
616 + $windid_table = $this->opdb->prefix . 'windid_user';
617 + $source_user = $this->opdb->get_row(
618 + $this->opdb->prepare( "SELECT legacy.password AS legacy_password, windid.password, windid.salt FROM {$legacy_table} AS legacy INNER JOIN {$windid_table} AS windid ON windid.uid = legacy.uid WHERE legacy.uid = %d LIMIT 1", $old_user_id ),
619 + ARRAY_A
620 + );
621 + if ( empty( $this->opdb->last_error ) ) {
622 + delete_transient( 'bbp_phpwind_source_connection_failed' );
623 + }
624 +
625 + if ( ! is_array( $source_user ) || ! isset( $source_user['legacy_password'], $source_user['password'], $source_user['salt'] ) || ! is_string( $source_user['legacy_password'] ) || ! is_string( $source_user['password'] ) || ! is_string( $source_user['salt'] ) || ! hash_equals( $stored_hash, $source_user['legacy_password'] ) ) {
626 + return false;
627 + }
628 +
629 + return serialize(
630 + array(
631 + 'hash' => $source_user['password'],
632 + 'salt' => $source_user['salt'],
633 + )
634 + );
635 + }
636 +
637 + /**
638 + * Replace a verified PHPWind hash with a WordPress password.
639 + *
640 + * @param int $user_id WordPress user ID.
641 + * @param string $password Password to hash for WordPress.
642 + */
643 + private function upgrade_user_pass( $user_id, $password ) {
644 + wp_set_password( $password, $user_id );
645 + delete_user_meta( $user_id, '_bbp_password' );
646 + delete_user_meta( $user_id, '_bbp_class' );
529 647 }
530 648
531 649 /**
532 650 * Translate the forum type from PHPWind v9.x Capitalised case to WordPress's non-capatilise case strings.