diff --git a/phpcs.xml.dist b/phpcs.xml.dist index d8c5651..99ba35a 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -6,7 +6,9 @@ - + + tests/* + @@ -24,4 +26,4 @@ tests/* - \ No newline at end of file + diff --git a/tests/Constants.php b/tests/Constants.php index 286a0f8..d767c6d 100644 --- a/tests/Constants.php +++ b/tests/Constants.php @@ -2,8 +2,6 @@ namespace Roots\PasswordBcrypt\Tests; -// phpcs:disable PHPCompatibility.Classes.NewConstVisibility.Found - class Constants { /** diff --git a/tests/TestCase.php b/tests/TestCase.php index 23048b0..c4bde75 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -5,8 +5,6 @@ use Brain\Monkey; use Mockery\Adapter\Phpunit\MockeryTestCase; -// phpcs:disable PHPCompatibility.FunctionDeclarations.NewReturnTypeDeclarations.voidFound - class TestCase extends MockeryTestCase { use MocksWpdb; diff --git a/tests/Unit/ApplicationPasswordTest.php b/tests/Unit/ApplicationPasswordTest.php new file mode 100644 index 0000000..3c2d387 --- /dev/null +++ b/tests/Unit/ApplicationPasswordTest.php @@ -0,0 +1,73 @@ +andReturn(true); + + $this + ->wpHasher() + ->shouldReceive('CheckPassword') + ->times(3) + ->andReturnValues([true, true, false]); + + expect('update_user_meta') + ->once() + ->withArgs(function (...$args) { + [$userId, $metaKey, $passwords] = $args; + + if ($userId != Constants::USER_ID) { + return false; + } + + if ($metaKey != \WP_Application_Passwords::USERMETA_KEY_APPLICATION_PASSWORDS) { + return false; + } + + if (count($passwords) != 3) { + return false; + } + + if (!key_exists(0, $passwords)) { + return false; + } + + $passwords = array_map((function ($item) { + return $item['password']; + }), $passwords); + + [$pw1, $pw2, $pw3] = $passwords; + + if (!password_verify(Constants::PASSWORD, $pw1)) { + return false; + } + + if (!password_verify(Constants::PASSWORD, $pw2)) { + return false; + } + + if (password_verify(Constants::PASSWORD, $pw3)) { + return false; + } + + return true; + }); + + $hash = wp_set_password(Constants::PASSWORD, Constants::USER_ID); + } +} diff --git a/tests/WPApplicationPasswords.php b/tests/WPApplicationPasswords.php new file mode 100644 index 0000000..cd7b3d9 --- /dev/null +++ b/tests/WPApplicationPasswords.php @@ -0,0 +1,25 @@ + Constants::PHPPASS_HASH + ], + [ + 'password' => Constants::BCRYPT_HASH + ], + [ + 'password' => Constants::INVALID_HASH + ] + ]; + } +} diff --git a/wp-password-bcrypt.php b/wp-password-bcrypt.php index eef184a..1b92d2d 100644 --- a/wp-password-bcrypt.php +++ b/wp-password-bcrypt.php @@ -86,14 +86,52 @@ function wp_hash_password($password) function wp_set_password($password, $user_id) { $hash = wp_hash_password($password); - global $wpdb; + $is_api_request = apply_filters( + 'application_password_is_api_request', + (defined('XMLRPC_REQUEST') && XMLRPC_REQUEST) || + (defined('REST_REQUEST') && REST_REQUEST) + ); + + if (! $is_api_request) { + global $wpdb; + + $wpdb->update($wpdb->users, [ + 'user_pass' => $hash, + 'user_activation_key' => '' + ], ['ID' => $user_id]); + + clean_user_cache($user_id); + + return $hash; + } + + if ( + ! class_exists('WP_Application_Passwords') || + empty($passwords = WP_Application_Passwords::get_user_application_passwords($user_id)) + ) { + return; + } + + global $wp_hasher; - $wpdb->update($wpdb->users, [ - 'user_pass' => $hash, - 'user_activation_key' => '' - ], ['ID' => $user_id]); + if (empty($wp_hasher)) { + require_once ABSPATH . WPINC . '/class-phpass.php'; + $wp_hasher = new PasswordHash(8, true); + } - clean_user_cache($user_id); + foreach ($passwords as $key => $value) { + if (! $wp_hasher->CheckPassword($password, $value['password'])) { + continue; + } + + $passwords[$key]['password'] = $hash; + } + + update_user_meta( + $user_id, + WP_Application_Passwords::USERMETA_KEY_APPLICATION_PASSWORDS, + $passwords + ); return $hash; }