From 4fb92f582675ba6b865d29b1b988604c645cd2d7 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 19 Apr 2021 14:08:16 -0500 Subject: [PATCH] work on rule --- ...Verifier.php => UncompromisedVerifier.php} | 2 +- .../Validation/NotPwnedVerifier.php | 8 +-- src/Illuminate/Validation/Rules/Password.php | 58 ++++++++++-------- .../Validation/ValidationServiceProvider.php | 15 ++--- .../Validation/ValidationPasswordRuleTest.php | 60 +++++-------------- 5 files changed, 58 insertions(+), 85 deletions(-) rename src/Illuminate/Contracts/Validation/{NotCompromisedVerifier.php => UncompromisedVerifier.php} (87%) diff --git a/src/Illuminate/Contracts/Validation/NotCompromisedVerifier.php b/src/Illuminate/Contracts/Validation/UncompromisedVerifier.php similarity index 87% rename from src/Illuminate/Contracts/Validation/NotCompromisedVerifier.php rename to src/Illuminate/Contracts/Validation/UncompromisedVerifier.php index 491abde78268..b9c124e2cddf 100644 --- a/src/Illuminate/Contracts/Validation/NotCompromisedVerifier.php +++ b/src/Illuminate/Contracts/Validation/UncompromisedVerifier.php @@ -2,7 +2,7 @@ namespace Illuminate\Contracts\Validation; -interface NotCompromisedVerifier +interface UncompromisedVerifier { /** * Verify that the given value has not been compromised in data leaks. diff --git a/src/Illuminate/Validation/NotPwnedVerifier.php b/src/Illuminate/Validation/NotPwnedVerifier.php index 2a2c24dd3b52..51df12507817 100644 --- a/src/Illuminate/Validation/NotPwnedVerifier.php +++ b/src/Illuminate/Validation/NotPwnedVerifier.php @@ -3,11 +3,11 @@ namespace Illuminate\Validation; use Exception; -use Illuminate\Contracts\Validation\NotCompromisedVerifier; +use Illuminate\Contracts\Validation\UncompromisedVerifier; use Illuminate\Http\Client\Factory; use Illuminate\Support\Str; -class NotPwnedVerifier implements NotCompromisedVerifier +class NotPwnedVerifier implements UncompromisedVerifier { /** * The http factory instance. @@ -64,9 +64,9 @@ protected function getHash($value) } /** - * Search by the given hash prefix and returns all occurrences. + * Search by the given hash prefix and returns all occurrences of leaked passwords. * - * @param string $hashPrefix + * @param string $hashPrefix * @return \Illuminate\Support\Collection */ protected function search($hashPrefix) diff --git a/src/Illuminate/Validation/Rules/Password.php b/src/Illuminate/Validation/Rules/Password.php index c6ba2b463c4d..7d75e9d73c22 100644 --- a/src/Illuminate/Validation/Rules/Password.php +++ b/src/Illuminate/Validation/Rules/Password.php @@ -2,20 +2,15 @@ namespace Illuminate\Validation\Rules; +use Illuminate\Container\Container; use Illuminate\Contracts\Validation\DataAwareRule; use Illuminate\Contracts\Validation\Rule; +use Illuminate\Contracts\Validation\UncompromisedVerifier; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Validator; class Password implements Rule, DataAwareRule { - /** - * If the password requires at least one uppercase and one lowercase letter. - * - * @var bool - */ - protected $caseDiff = false; - /** * The data under validation. * @@ -24,25 +19,25 @@ class Password implements Rule, DataAwareRule protected $data; /** - * If the password requires at least one letter. + * The minimum size of the password. * - * @var bool + * @var int */ - protected $letters = false; + protected $min = 8; /** - * The minimum size of the password. + * If the password requires at least one uppercase and one lowercase letter. * - * @var int + * @var bool */ - protected $min = 8; + protected $mixedCase = false; /** - * If the password should has not been compromised in data leaks. + * If the password requires at least one letter. * * @var bool */ - protected $notCompromised = false; + protected $letters = false; /** * If the password requires at least one number. @@ -58,6 +53,13 @@ class Password implements Rule, DataAwareRule */ protected $symbols = false; + /** + * If the password should has not been compromised in data leaks. + * + * @var bool + */ + protected $uncompromised = false; + /** * The failure messages, if any. * @@ -105,9 +107,9 @@ public static function min($size) * * @return $this */ - public function ensureNotCompromised() + public function uncompromised() { - $this->notCompromised = true; + $this->uncompromised = true; return $this; } @@ -117,9 +119,9 @@ public function ensureNotCompromised() * * @return $this */ - public function requireCaseDiff() + public function mixedCase() { - $this->caseDiff = true; + $this->mixedCase = true; return $this; } @@ -129,7 +131,7 @@ public function requireCaseDiff() * * @return $this */ - public function requireLetters() + public function letters() { $this->letters = true; @@ -141,7 +143,7 @@ public function requireLetters() * * @return $this */ - public function requireNumbers() + public function numbers() { $this->numbers = true; @@ -153,7 +155,7 @@ public function requireNumbers() * * @return $this */ - public function requireSymbols() + public function symbols() { $this->symbols = true; @@ -170,7 +172,7 @@ public function requireSymbols() public function passes($attribute, $value) { $validator = Validator::make($this->data, [ - $attribute => 'required|string|confirmed|min:'.$this->min, + $attribute => 'string|min:'.$this->min, ]); if ($validator->fails()) { @@ -179,7 +181,7 @@ public function passes($attribute, $value) $value = (string) $value; - if ($this->caseDiff && ! preg_match('/(\p{Ll}+.*\p{Lu})|(\p{Lu}+.*\p{Ll})/u', $value)) { + if ($this->mixedCase && ! preg_match('/(\p{Ll}+.*\p{Lu})|(\p{Lu}+.*\p{Ll})/u', $value)) { $this->fail('The :attribute must contain at least one uppercase and one lowercase letter.'); } @@ -199,7 +201,7 @@ public function passes($attribute, $value) return false; } - if ($this->notCompromised && ! app('validation.not_compromised')->verify($value)) { + if ($this->uncompromised && ! Container::getInstance()->make(UncompromisedVerifier::class)->verify($value)) { return $this->fail( 'The given :attribute has appeared in a data leak. Please choose a different :attribute.' ); @@ -226,7 +228,11 @@ public function message() */ protected function fail($messages) { - $this->messages = array_merge($this->messages, Arr::wrap($messages)); + $messages = collect(Arr::wrap($messages))->map(function ($message) { + return __($message); + })->all(); + + $this->messages = array_merge($this->messages, $messages); return false; } diff --git a/src/Illuminate/Validation/ValidationServiceProvider.php b/src/Illuminate/Validation/ValidationServiceProvider.php index 552b58730a62..936235f9e7bb 100755 --- a/src/Illuminate/Validation/ValidationServiceProvider.php +++ b/src/Illuminate/Validation/ValidationServiceProvider.php @@ -3,6 +3,7 @@ namespace Illuminate\Validation; use Illuminate\Contracts\Support\DeferrableProvider; +use Illuminate\Contracts\Validation\UncompromisedVerifier; use Illuminate\Http\Client\Factory as HttpFactory; use Illuminate\Support\ServiceProvider; @@ -16,9 +17,7 @@ class ValidationServiceProvider extends ServiceProvider implements DeferrablePro public function register() { $this->registerPresenceVerifier(); - - $this->registerNotCompromisedVerifier(); - + $this->registerUncompromisedVerifier(); $this->registerValidationFactory(); } @@ -56,16 +55,14 @@ protected function registerPresenceVerifier() } /** - * Register the not compromised verifier. + * Register the uncompromised password verifier. * * @return void */ - protected function registerNotCompromisedVerifier() + protected function registerUncompromisedVerifier() { - $this->app->singleton('validation.not_compromised', function ($app) { - return new NotPwnedVerifier( - $app[HttpFactory::class] - ); + $this->app->singleton(UncompromisedVerifier::class, function ($app) { + return new NotPwnedVerifier($app[HttpFactory::class]); }); } diff --git a/tests/Validation/ValidationPasswordRuleTest.php b/tests/Validation/ValidationPasswordRuleTest.php index a3ed6a9bd438..2611817e3f4f 100644 --- a/tests/Validation/ValidationPasswordRuleTest.php +++ b/tests/Validation/ValidationPasswordRuleTest.php @@ -13,15 +13,6 @@ class ValidationPasswordRuleTest extends TestCase { - public function testRequired() - { - $this->fails(Password::min(3), [null], [ - 'validation.required', - ]); - - $this->passes(Password::min(3), ['1234', 'abcd', 'a z s']); - } - public function testString() { $this->fails(Password::min(3), [['foo' => 'bar'], ['foo']], [ @@ -47,43 +38,43 @@ public function testMin() public function testCaseDiff() { - $this->fails(Password::min(2)->requireCaseDiff(), ['nn', 'MM'], [ + $this->fails(Password::min(2)->mixedCase(), ['nn', 'MM'], [ 'The my password must contain at least one uppercase and one lowercase letter.', ]); - $this->passes(Password::min(2)->requireCaseDiff(), ['Nn', 'Mn', 'âA']); + $this->passes(Password::min(2)->mixedCase(), ['Nn', 'Mn', 'âA']); } public function testLetters() { - $this->fails(Password::min(2)->requireLetters(), ['11', '22', '^^', '``', '**'], [ + $this->fails(Password::min(2)->letters(), ['11', '22', '^^', '``', '**'], [ 'The my password must contain at least one letter.', ]); - $this->passes(Password::min(2)->requireLetters(), ['1a', 'b2', 'â1']); + $this->passes(Password::min(2)->letters(), ['1a', 'b2', 'â1']); } public function testNumbers() { - $this->fails(Password::min(2)->requireNumbers(), ['aa', 'bb', ' a'], [ + $this->fails(Password::min(2)->numbers(), ['aa', 'bb', ' a'], [ 'The my password must contain at least one number.', ]); - $this->passes(Password::min(2)->requireNumbers(), ['1a', 'b2', '00']); + $this->passes(Password::min(2)->numbers(), ['1a', 'b2', '00']); } public function testSymbols() { - $this->fails(Password::min(2)->requireSymbols(), ['ab', '1v'], [ + $this->fails(Password::min(2)->symbols(), ['ab', '1v'], [ 'The my password must contain at least one symbol.', ]); - $this->passes(Password::min(2)->requireSymbols(), ['n^d', 'd^!', 'âè']); + $this->passes(Password::min(2)->symbols(), ['n^d', 'd^!', 'âè']); } public function testNotCompromised() { - $this->fails(Password::min(2)->ensureNotCompromised(), [ + $this->fails(Password::min(2)->uncompromised(), [ '123456', 'password', 'welcome', @@ -96,7 +87,7 @@ public function testNotCompromised() 'The given my password has appeared in a data leak. Please choose a different my password.', ]); - $this->passes(Password::min(2)->ensureNotCompromised(), [ + $this->passes(Password::min(2)->uncompromised(), [ '!p8VrB', '&xe6VeKWF#n4', '%HurHUnw7zM!', @@ -110,11 +101,11 @@ public function testMessages() { $makeRule = function () { return Password::min(8) - ->requireCaseDiff() - ->requireLetters() - ->requireNumbers() - ->requireSymbols() - ->ensureNotCompromised(); + ->mixedCase() + ->letters() + ->numbers() + ->symbols() + ->uncompromised(); }; $this->fails($makeRule(), ['foo', 'azdazd', '1231231'], [ @@ -134,27 +125,6 @@ public function testMessages() ]); } - public function testConfirmed() - { - $v = new Validator( - resolve('translator'), - ['my_password' => '1234', 'my_password_confirmation' => '5678'], - ['my_password' => Password::min(3)] - ); - - $this->assertSame(false, $v->passes()); - $this->assertSame(['my_password' => ['validation.confirmed']], $v->messages()->toArray()); - - $v = new Validator( - resolve('translator'), - ['my_password' => '1234'], - ['my_password' => Password::min(3)] - ); - - $this->assertSame(false, $v->passes()); - $this->assertSame(['my_password' => ['validation.confirmed']], $v->messages()->toArray()); - } - protected function passes($rule, $values) { $this->testRule($rule, $values, true, []);