| @@ -9,9 +9,9 @@ | ||
| 9 | 9 | |
| 10 | 10 | /** |
| 11 | 11 | * Implementation of FluxBB Forum converter. |
| 12 | 12 | * |
| 13 | - * @since 2.5.0 bbPress (r5138) | |
| 13 | + * @since 2.5.0 bbPress (r5139) | |
| 14 | 14 | * |
| 15 | 15 | * @link Codex Docs https://codex.bbpress.org/import-forums/fluxbb |
| 16 | 16 | */ |
| 17 | 17 | class FluxBB extends BBP_Converter_Base { |
| @@ -16,8 +16,14 @@ | ||
| 16 | 16 | */ |
| 17 | 17 | class FluxBB extends BBP_Converter_Base { |
| 18 | 18 | |
| 19 | 19 | /** |
| 20 | + * @var bool Whether source-dependent fields have been set up. | |
| 21 | + * @since 2.6.18 bbPress (r7588) | |
| 22 | + */ | |
| 23 | + private $source_fields_setup = false; | |
| 24 | + | |
| 25 | + /** | |
| 20 | 26 | * Main Constructor |
| 21 | 27 | * |
| 22 | 28 | */ |
| 23 | 29 | public function __construct() { |
| @@ -452,19 +458,11 @@ | ||
| 452 | 458 | 'to_fieldname' => '_bbp_password', |
| 453 | 459 | 'callback_method' => 'callback_savepass' |
| 454 | 460 | ); |
| 455 | 461 | |
| 456 | - // Store old user salt (This is only used for the SELECT row info for the above password save) | |
| 457 | -// $this->field_map[] = array( | |
| 458 | -// 'from_tablename' => 'users', | |
| 459 | -// 'from_fieldname' => 'salt', | |
| 460 | -// 'to_type' => 'user', | |
| 461 | -// 'to_fieldname' => '' | |
| 462 | -// ); | |
| 463 | - | |
| 464 | 462 | // User password verify class (Stored in usermeta for verifying password) |
| 465 | 463 | $this->field_map[] = array( |
| 466 | - 'to_type' => 'users', | |
| 464 | + 'to_type' => 'user', | |
| 467 | 465 | 'to_fieldname' => '_bbp_class', |
| 468 | 466 | 'default' => 'FluxBB' |
| 469 | 467 | ); |
| 470 | 468 | |
| @@ -591,16 +589,52 @@ | ||
| 591 | 589 | return ''; |
| 592 | 590 | } |
| 593 | 591 | |
| 594 | 592 | /** |
| 595 | - * This method is to save the salt and password together. That | |
| 596 | - * way when we authenticate it we can get it out of the database | |
| 597 | - * as one value. Array values are auto sanitized by WordPress. | |
| 593 | + * Setup the optional legacy salt field after connecting to the source. | |
| 594 | + * | |
| 595 | + * @since 2.6.18 bbPress (r7588) | |
| 598 | 596 | */ |
| 597 | + protected function setup_source_fields() { | |
| 598 | + if ( $this->source_fields_setup ) { | |
| 599 | + return; | |
| 600 | + } | |
| 601 | + | |
| 602 | + $this->source_fields_setup = true; | |
| 603 | + | |
| 604 | + if ( $this->source_has_salt() ) { | |
| 605 | + $this->field_map[] = array( | |
| 606 | + 'from_tablename' => 'users', | |
| 607 | + 'from_fieldname' => 'salt', | |
| 608 | + 'to_type' => 'user', | |
| 609 | + 'to_fieldname' => '' | |
| 610 | + ); | |
| 611 | + } | |
| 612 | + } | |
| 613 | + | |
| 614 | + /** | |
| 615 | + * Check whether the source users table retains the legacy FluxBB salt field. | |
| 616 | + * | |
| 617 | + * @since 2.6.18 bbPress (r7538) | |
| 618 | + * | |
| 619 | + * @return bool True when the salt field exists, false otherwise. | |
| 620 | + */ | |
| 621 | + private function source_has_salt() { | |
| 622 | + if ( empty( $this->opdb ) ) { | |
| 623 | + return false; | |
| 624 | + } | |
| 625 | + | |
| 626 | + return (bool) $this->opdb->get_var( "SHOW COLUMNS FROM {$this->opdb->prefix}users LIKE 'salt'" ); | |
| 627 | + } | |
| 628 | + | |
| 629 | + /** | |
| 630 | + * Save the salt and password together. Pre-slash the salt because WordPress | |
| 631 | + * removes one layer of slashes when storing user metadata. | |
| 632 | + */ | |
| 599 | 633 | public function callback_savepass( $field, $row ) { |
| 600 | 634 | $pass_array = array( |
| 601 | 635 | 'hash' => $field, |
| 602 | - 'salt' => $row['salt'] | |
| 636 | + 'salt' => isset( $row['salt'] ) ? wp_slash( (string) $row['salt'] ) : '' | |
| 603 | 637 | ); |
| 604 | 638 | |
| 605 | 639 | return $pass_array; |
| 606 | 640 | } |
| @@ -611,25 +645,37 @@ | ||
| 611 | 645 | */ |
| 612 | 646 | public function authenticate_pass( $password, $serialized_pass ) { |
| 613 | 647 | |
| 614 | 648 | // Unserialize the password, with safeguards |
| 615 | - $pass_array = unserialize( | |
| 616 | - $serialized_pass, | |
| 617 | - array( | |
| 618 | - 'allowed_classes' => false, | |
| 619 | - 'max_depth' => 1 | |
| 620 | - ) | |
| 621 | - ); | |
| 649 | + $pass_array = $this->unserialize_pass( $serialized_pass ); | |
| 622 | 650 | |
| 623 | - // Bail if missing values | |
| 624 | - if ( ! is_array( $pass_array ) || ! isset( $pass_array['hash'], $pass_array['salt'] ) ) { | |
| 651 | + // Bail if missing or invalid values | |
| 652 | + if ( ! is_array( $pass_array ) || ! isset( $pass_array['hash'] ) || ! array_key_exists( 'salt', $pass_array ) || ! is_string( $pass_array['hash'] ) || ( ! is_string( $pass_array['salt'] ) && ! is_null( $pass_array['salt'] ) ) ) { | |
| 625 | 653 | return false; |
| 626 | 654 | } |
| 627 | 655 | |
| 628 | - // Return comparison | |
| 656 | + $salt = (string) $pass_array['salt']; | |
| 657 | + | |
| 658 | + // Salted SHA-1 from FluxBB 1.3 | |
| 659 | + if ( ! empty( $salt ) ) { | |
| 660 | + return hash_equals( | |
| 661 | + $pass_array['hash'], | |
| 662 | + sha1( $salt . sha1( $password ) ) | |
| 663 | + ); | |
| 664 | + } | |
| 665 | + | |
| 666 | + // Unsalted MD5 from FluxBB 1.2 | |
| 667 | + if ( 40 !== strlen( $pass_array['hash'] ) ) { | |
| 668 | + return hash_equals( | |
| 669 | + $pass_array['hash'], | |
| 670 | + md5( $password ) | |
| 671 | + ); | |
| 672 | + } | |
| 673 | + | |
| 674 | + // SHA-1 from FluxBB 1.4 and newer | |
| 629 | 675 | return hash_equals( |
| 630 | 676 | $pass_array['hash'], |
| 631 | - md5( md5( $password ) . $pass_array['salt'] ) | |
| 677 | + sha1( $password ) | |
| 632 | 678 | ); |
| 633 | 679 | } |
| 634 | 680 | |
| 635 | 681 | /** |