Rework dictionary validator, refactoring (#20)
* Update meta * Rewrite to rule-based validation * New tests and testing framework * Minor restructure and cleanup * Update README.md * Copy-tweaks. Drop PHP 7.3 * Fix message redout in older Laravel-versions
This commit is contained in:
parent
1ea671c7fe
commit
3d6e0448e4
|
|
@ -0,0 +1,2 @@
|
|||
github: olssonm
|
||||
custom: https://marcusolsson.me/kontakta
|
||||
|
|
@ -21,8 +21,6 @@ jobs:
|
|||
illuminate: ^8.0
|
||||
- php: 7.4
|
||||
illuminate: ^7.0
|
||||
- php: 7.3
|
||||
illuminate: ^7.0
|
||||
|
||||
name: PHP ${{ matrix.php }} - Illuminate ${{ matrix.illuminate }}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2020 Marcus Olsson <contact@marcusolsson.me>
|
||||
Copyright (c) 2022 Marcus Olsson <contact@marcusolsson.me>
|
||||
|
||||
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
> of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
|||
132
README.md
132
README.md
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
A simple implementation of zxcvbn for Laravel. This package allows you to access "zxcvbn-related" data on a passphrase in the application and also to use zxcvbn as a standard validator.
|
||||
|
||||
Uses [Zxcvbn-PHP](https://github.com/bjeavons/zxcvbn-php) by [@bjeavons](https://github.com/bjeavons) and [@mkopinsky](https://github.com/mkopinsky), which in turn is inspired by [zxcvbn](https://github.com/dropbox/zxcvbn) by [@dropbox](https://github.com/dropbox).
|
||||
Uses [Zxcvbn-PHP](https://github.com/bjeavons/zxcvbn-php) by [@bjeavons](https://github.com/bjeavons), which in turn is inspired by [zxcvbn](https://github.com/dropbox/zxcvbn) by [@dropbox](https://github.com/dropbox).
|
||||
|
||||
## Install
|
||||
|
||||
|
|
@ -33,9 +33,7 @@ If you've added `Olssonm\Zxcvbn` as an alias, your can access Zxcvbn easily from
|
|||
|
||||
### "In app"
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
``` php
|
||||
use Zxcvbn;
|
||||
|
||||
class MyClass extends MyOtherClass
|
||||
|
|
@ -47,14 +45,29 @@ class MyClass extends MyOtherClass
|
|||
|
||||
// array:9 [
|
||||
// "password" => "password"
|
||||
// "guesses" => 3
|
||||
// "guesses" => 3.0
|
||||
// "guesses_log10" => 0.47712125471966
|
||||
// "sequence" => array:1 []
|
||||
// "crack_times_seconds" => array:4 []
|
||||
// "crack_times_display" => array:4 []
|
||||
// "sequence" => [],
|
||||
// "crack_times_seconds" => array:4 [
|
||||
// "online_throttling_100_per_hour" => 108.0
|
||||
// "online_no_throttling_10_per_second" => 0.3
|
||||
// "offline_slow_hashing_1e4_per_second" => 0.0003
|
||||
// "offline_fast_hashing_1e10_per_second" => 3.0E-10
|
||||
// ]
|
||||
// "crack_times_display" => array:4 [
|
||||
// "online_throttling_100_per_hour" => "2 minutes"
|
||||
// "online_no_throttling_10_per_second" => "less than a second"
|
||||
// "offline_slow_hashing_1e4_per_second" => "less than a second"
|
||||
// "offline_fast_hashing_1e10_per_second" => "less than a second"
|
||||
// ]
|
||||
// "score" => 0
|
||||
// "feedback" => array:2 []
|
||||
// "calc_time" => 0.042769908905029
|
||||
// "feedback" => array:2 [
|
||||
// "warning" => "This is a top-10 common password"
|
||||
// "suggestions" => array:1 [
|
||||
// 0 => "Add another word or two. Uncommon words are better."
|
||||
// ]
|
||||
// ]
|
||||
// "calc_time" => 0.020488977432251
|
||||
// ]
|
||||
}
|
||||
}
|
||||
|
|
@ -64,71 +77,68 @@ Play around with different passwords and phrases, the results may surprise you.
|
|||
|
||||
### As a validator
|
||||
|
||||
The package gives you two different validation rules that you may use; `zxcvbn_min` and `zxcvbn_dictionary`.
|
||||
The package makes two types of validations available for your application. `zxcvbn` and `zxcvbn_dictionary`.
|
||||
|
||||
#### zxcvbn_min
|
||||
### zxcvbn
|
||||
|
||||
`zxcvbn_min` allows you to set up a rule for minimum score that the value beeing tested should adhere to.
|
||||
With this rule you set the lowest score that the phrase need to score wuth Zxcvbn to pass.
|
||||
|
||||
**Syntax**
|
||||
|
||||
input' => 'zxcvbn_min:min_value'
|
||||
|
||||
**Example**
|
||||
|
||||
```php
|
||||
<?php
|
||||
$data = ['password' => 'password'];
|
||||
$validator = Validator::make($data, [
|
||||
'password' => 'zxcvbn_min:3|required',
|
||||
], [
|
||||
'password.zxcvbn_min' => 'Your password is not strong enough!'
|
||||
]);
|
||||
``` php
|
||||
'input' => 'zxcvbn:min_value'
|
||||
```
|
||||
|
||||
In this example the password should at least have a "score" of three (3) to pass the validation. Of course, you should probably use the zxcvbn-library on the front-end too to allow the user to know this before posting the form...
|
||||
**Examples**
|
||||
|
||||
#### zxcvbn_dictionary
|
||||
``` php
|
||||
$request->validate([
|
||||
'password' => 'required|zxcvbn:3'
|
||||
]);
|
||||
```
|
||||
|
||||
This is a bit more interesting. `zxcvbn_dictionary` allows you to input both the users username and/or email, and their password. The validator checks that the password doesn't exist in the username, or that they are too similar.
|
||||
You may also initialize the rule as an object:
|
||||
|
||||
``` php
|
||||
use Olssonm\Zxcvbn\Rules\Zxcvbn;
|
||||
|
||||
function rules()
|
||||
{
|
||||
return [
|
||||
'password' => ['required', new Zxcvbn($minScore = 3)]
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
In this example the password should at least have a "score" of three (3) to pass the validation. Of course, you should probably use the [zxcvbn-library](https://github.com/dropbox/zxcvbn) on the front-end too to allow the user to know this before posting the form.
|
||||
|
||||
### zxcvbn_dictionary
|
||||
|
||||
This is a bit more interesting. `zxcvbn_dictionary` allows you to input both the users username and/or email together with their password (you need suply one piece of user input). The validator checks that the password doesn't exist in the username, or that they are too similar.
|
||||
|
||||
**Syntax**
|
||||
|
||||
'input' => 'xcvbn_dictionary:username,email'
|
||||
``` php
|
||||
'input' => 'zxcvbn_dictionary:input1,input2'
|
||||
```
|
||||
|
||||
**Example**
|
||||
**Examples**
|
||||
|
||||
```php
|
||||
<?php
|
||||
/**
|
||||
* Example 1, pass
|
||||
*/
|
||||
$password = '31??2sa//"dhjd2askjd19sad19!!&!#"';
|
||||
$data = [
|
||||
'username' => 'user',
|
||||
'email' => 'trash@thedumpster.com'
|
||||
``` php
|
||||
$request->validate([
|
||||
'password' => sprintf('required|zxcvbn_dictionary:%s,%s', $request->username, $request->email)
|
||||
]);
|
||||
```
|
||||
|
||||
``` php
|
||||
use Olssonm\Zxcvbn\Rules\ZxcvbnDictionary;
|
||||
|
||||
function rules()
|
||||
{
|
||||
return [
|
||||
'password' => ['required', new ZxcvbnDictionary($this->username)]
|
||||
];
|
||||
$validator = Validator::make($password, [
|
||||
'password' => sprintf('required|zxcvbn_dictionary:%s,%s', $data['username'], $data['email'])
|
||||
]);
|
||||
|
||||
dd($validator->passes());
|
||||
// true
|
||||
|
||||
/**
|
||||
* Example 2, fail
|
||||
*/
|
||||
$password = 'mycomplicatedphrase';
|
||||
$data = [
|
||||
'username' => 'mycomplicatedphrase',
|
||||
'email' => 'mycomplicatedphrase@thedumpster.com'
|
||||
];
|
||||
$validator = Validator::make($password, [
|
||||
'password' => sprintf('required|zxcvbn_dictionary:%s,%s', $data['username'], $data['email'])
|
||||
]);
|
||||
|
||||
dd($validator->passes());
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
|
@ -147,7 +157,7 @@ $ phpunit
|
|||
|
||||
The MIT License (MIT). Please see the [License File](LICENSE.md) for more information.
|
||||
|
||||
© 2020 [Marcus Olsson](https://marcusolsson.me).
|
||||
© 2022 [Marcus Olsson](https://marcusolsson.me).
|
||||
|
||||
[ico-version]: https://img.shields.io/packagist/v/olssonm/l5-zxcvbn.svg?style=flat-square
|
||||
|
||||
|
|
|
|||
|
|
@ -20,13 +20,15 @@
|
|||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^7.3|^8.0",
|
||||
"php": "^7.4|^8.0",
|
||||
"illuminate/support": "^7.0|^8.0|^9.0",
|
||||
"bjeavons/zxcvbn-php": "^1.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^8.0|^9.0",
|
||||
"orchestra/testbench": ">=4.0"
|
||||
"orchestra/testbench": ">=4.0",
|
||||
"pestphp/pest": "^1.22",
|
||||
"squizlabs/php_codesniffer": "^3.7"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
|
@ -39,11 +41,14 @@
|
|||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": "phpunit"
|
||||
"test": "./vendor/bin/pest",
|
||||
"coverage": "XDEBUG_MODE=coverage; ./vendor/bin/pest --coverage",
|
||||
"phpsniff": "vendor/bin/phpcs --standard=\"PSR12\" ./src",
|
||||
"phpfix": "vendor/bin/phpcbf --standard=\"PSR12\" ./src"
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.x-dev"
|
||||
"dev-master": "5.x-dev"
|
||||
},
|
||||
"laravel": {
|
||||
"providers": [
|
||||
|
|
@ -52,5 +57,10 @@
|
|||
}
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
"prefer-stable": true,
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"pestphp/pest-plugin": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
namespace Olssonm\Zxcvbn\Rules;
|
||||
|
||||
use Illuminate\Contracts\Validation\Rule;
|
||||
use ZxcvbnPhp\Zxcvbn as ZxcvbnPhp;
|
||||
|
||||
class Zxcvbn implements Rule
|
||||
{
|
||||
private $target;
|
||||
|
||||
/**
|
||||
* Create a new rule instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($target = 5)
|
||||
{
|
||||
$this->target = $target;
|
||||
}
|
||||
|
||||
public static function handle(): string
|
||||
{
|
||||
return 'zxcvbn';
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the validation rule passes.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function passes($attribute, $value)
|
||||
{
|
||||
$zxcvbn = (new ZxcvbnPhp())->passwordStrength($value);
|
||||
return ($zxcvbn['score'] >= $this->target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation error message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function message()
|
||||
{
|
||||
return 'The :attribute is not strong enough.';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
namespace Olssonm\Zxcvbn\Rules;
|
||||
|
||||
use Illuminate\Contracts\Validation\Rule;
|
||||
use ZxcvbnPhp\Matchers\DictionaryMatch;
|
||||
|
||||
class ZxcvbnDictionary implements Rule
|
||||
{
|
||||
protected array $input;
|
||||
|
||||
/**
|
||||
* Create a new rule instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($input1 = null, $input2 = null)
|
||||
{
|
||||
$this->input = array_filter([$input1, $input2]);
|
||||
}
|
||||
|
||||
public static function handle(): string
|
||||
{
|
||||
return 'zxcvbn_dictionary';
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the validation rule passes.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function passes($attribute, $value)
|
||||
{
|
||||
$matches = DictionaryMatch::match($value, $this->input);
|
||||
$matches = array_values(array_filter($matches, function ($match) {
|
||||
return $match->dictionaryName === 'user_inputs';
|
||||
}));
|
||||
|
||||
return count($matches) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation error message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function message()
|
||||
{
|
||||
return 'The :attribute is too simililar to another field.';
|
||||
}
|
||||
}
|
||||
|
|
@ -2,71 +2,15 @@
|
|||
|
||||
namespace Olssonm\Zxcvbn;
|
||||
|
||||
use ZxcvbnPhp\Zxcvbn as ZxcvbnPhp;
|
||||
use Illuminate\Contracts\Validation\Factory;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Olssonm\Zxcvbn\Rules\Zxcvbn;
|
||||
use Olssonm\Zxcvbn\Rules\ZxcvbnDictionary;
|
||||
use Validator;
|
||||
use ZxcvbnPhp\Zxcvbn as ZxcvbnPhp;
|
||||
|
||||
class ZxcvbnServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Perform post-registration booting of services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
/**
|
||||
* Extend the Laravel Validator with the "zxcvbn_min" rule
|
||||
*/
|
||||
Validator::extend('zxcvbn_min', function($attribute, $value, $parameters) {
|
||||
$zxcvbn = new ZxcvbnPhp();
|
||||
$zxcvbn = $zxcvbn->passwordStrength($value);
|
||||
$target = 5;
|
||||
|
||||
if (isset($parameters[0])) {
|
||||
$target = $parameters[0];
|
||||
}
|
||||
|
||||
return ($zxcvbn['score'] >= $target);
|
||||
}, 'Your :attribute is not secure enough.');
|
||||
|
||||
Validator::replacer('zxcvbn_min', function($message, $attribute) {
|
||||
$message = str_replace(':attribute', $attribute, $message);
|
||||
return $message;
|
||||
});
|
||||
|
||||
/**
|
||||
* Extend the Laravel Validator with the "zxcvbn_dictionary" rule
|
||||
*/
|
||||
Validator::extend('zxcvbn_dictionary', function($attribute, $value, $parameters) {
|
||||
$email = null;
|
||||
$username = null;
|
||||
|
||||
if (isset($parameters[0])) {
|
||||
$email = $parameters[0];
|
||||
$username = $parameters[1];
|
||||
}
|
||||
|
||||
$zxcvbn = new ZxcvbnPhp();
|
||||
$zxcvbn = $zxcvbn->passwordStrength($value, [$username, $email]);
|
||||
|
||||
if (isset($zxcvbn['sequence'][0])) {
|
||||
$dictionary = $zxcvbn['sequence'][0];
|
||||
if (isset($dictionary->dictionaryName)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}, 'Your :attribute is insecure. It either matches a commonly used password, or you have used a similar username/password combination.');
|
||||
|
||||
Validator::replacer('zxcvbn_dictionary', function($message, $attribute) {
|
||||
$message = str_replace(':attribute', $attribute, $message);
|
||||
return $message;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register any package services.
|
||||
*
|
||||
|
|
@ -74,8 +18,18 @@ class ZxcvbnServiceProvider extends ServiceProvider
|
|||
*/
|
||||
public function register()
|
||||
{
|
||||
$this->app->bind('zxcvbn', function() {
|
||||
$this->app->bind('zxcvbn', function () {
|
||||
return new ZxcvbnPhp();
|
||||
});
|
||||
}
|
||||
|
||||
public function boot()
|
||||
{
|
||||
foreach ([Zxcvbn::class, ZxcvbnDictionary::class] as $rule) {
|
||||
$this->app['validator']->extend($rule::handle(), function ($attribute, $value, $parameters) use ($rule) {
|
||||
return (new $rule(...$parameters))->passes($attribute, $value);
|
||||
},
|
||||
(new $rule())->message());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
namespace Olssonm\Zxcvbn\Test;
|
||||
|
||||
uses(TestCase::class)->in(__DIR__);
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace Olssonm\Zxcvbn\Test;
|
||||
|
||||
use Olssonm\Zxcvbn\ZxcvbnServiceProvider;
|
||||
use Orchestra\Testbench\TestCase as OrchestraTestCase;
|
||||
|
||||
abstract class TestCase extends OrchestraTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
protected function getPackageProviders($app)
|
||||
{
|
||||
return [
|
||||
ZxcvbnServiceProvider::class
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,160 +1,131 @@
|
|||
<?php namespace Olssonm\Zxcvbn\Tests;
|
||||
<?php
|
||||
|
||||
use Validator;
|
||||
namespace Olssonm\Zxcvbn\Test;
|
||||
|
||||
use Zxcvbn;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Olssonm\Zxcvbn\Facades\Zxcvbn;
|
||||
use Olssonm\Zxcvbn\Rules\Zxcvbn as ZxcvbnRule;
|
||||
use Olssonm\Zxcvbn\Rules\ZxcvbnDictionary as ZxcvbnDictionaryRule;
|
||||
use Olssonm\Zxcvbn\ZxcvbnServiceProvider;
|
||||
use ZxcvbnPhp\Zxcvbn as ZxcvbnPhp;
|
||||
|
||||
class ZxcvbnTest extends \Orchestra\Testbench\TestCase {
|
||||
it('loads package', function () {
|
||||
$providers = $this->app->getLoadedProviders();
|
||||
$this->assertTrue(array_key_exists(ZxcvbnServiceProvider::class, $providers));
|
||||
});
|
||||
|
||||
public function setUp(): void {
|
||||
parent::setUp();
|
||||
}
|
||||
it('loads facade', function () {
|
||||
$facade = $this->app['zxcvbn'];
|
||||
$this->assertTrue(is_a($facade, ZxcvbnPhp::class));
|
||||
});
|
||||
|
||||
/**
|
||||
* Load the package
|
||||
* @return array the packages
|
||||
*/
|
||||
protected function getPackageProviders($app)
|
||||
{
|
||||
return [
|
||||
'Olssonm\Zxcvbn\ZxcvbnServiceProvider'
|
||||
];
|
||||
}
|
||||
it('can perform zxcvbn basics', function () {
|
||||
$zxcvbn = Zxcvbn::passwordStrength('password');
|
||||
|
||||
/**
|
||||
* Load the alias
|
||||
* @return array the aliases
|
||||
*/
|
||||
protected function getPackageAliases($app)
|
||||
{
|
||||
return [
|
||||
'Zxcvbn' => 'Olssonm\Zxcvbn\Facades\Zxcvbn'
|
||||
];
|
||||
}
|
||||
$testVar1 = Zxcvbn::passwordStrength('test');
|
||||
|
||||
/**
|
||||
* Just run som standard tests to see that Zxcvbn is up to snuff and working
|
||||
* @test
|
||||
*/
|
||||
public function test_zxcvbn_basics()
|
||||
{
|
||||
$zxcvbn = Zxcvbn::passwordStrength('password');
|
||||
// Check keys
|
||||
$this->assertArrayHasKey('score', $testVar1);
|
||||
$this->assertArrayHasKey('sequence', $testVar1);
|
||||
$this->assertArrayHasKey('crack_times_seconds', $testVar1);
|
||||
$this->assertArrayHasKey('crack_times_display', $testVar1);
|
||||
$this->assertArrayHasKey('calc_time', $testVar1);
|
||||
$this->assertArrayHasKey('guesses', $testVar1);
|
||||
|
||||
$testVar1 = Zxcvbn::passwordStrength('test');
|
||||
// Check score-value
|
||||
$this->assertEquals(0, $testVar1['score']);
|
||||
|
||||
// Check keys
|
||||
$this->assertArrayHasKey('score', $testVar1);
|
||||
$this->assertArrayHasKey('sequence', $testVar1);
|
||||
$this->assertArrayHasKey('crack_times_seconds', $testVar1);
|
||||
$this->assertArrayHasKey('crack_times_display', $testVar1);
|
||||
$this->assertArrayHasKey('calc_time', $testVar1);
|
||||
$this->assertArrayHasKey('guesses', $testVar1);
|
||||
// Run some more tests
|
||||
$testVar2 = Zxcvbn::passwordStrength('dadaurka');
|
||||
$testVar3 = Zxcvbn::passwordStrength('staple horse battery');
|
||||
$testVar4 = Zxcvbn::passwordStrength('7E6k9axB*gwGHa&aZTohmD9Wr&NVs[b4'); //<-- 32
|
||||
|
||||
// Check score-value
|
||||
$this->assertEquals(0, $testVar1['score']);
|
||||
// Check score-value
|
||||
$this->assertEquals(2, $testVar2['score']);
|
||||
$this->assertEquals(4, $testVar3['score']);
|
||||
$this->assertEquals(4, $testVar4['score']);
|
||||
});
|
||||
|
||||
// Run some more tests
|
||||
$testVar2 = Zxcvbn::passwordStrength('dadaurka');
|
||||
$testVar3 = Zxcvbn::passwordStrength('staple horse battery');
|
||||
$testVar4 = Zxcvbn::passwordStrength('7E6k9axB*gwGHa&aZTohmD9Wr&NVs[b4'); //<-- 32
|
||||
it('can validate min-rule', function () {
|
||||
// Fails: returns message
|
||||
$this->assertEquals('Just a test message', min_validation('test', 4, 'Just a test message'));
|
||||
$this->assertEquals('Just another test message', min_validation('test', 4, 'Just another test message'));
|
||||
$this->assertEquals('The password is not strong enough.', min_validation('staple horse battery', 5, null));
|
||||
|
||||
// Check score-value
|
||||
$this->assertEquals(2, $testVar2['score']);
|
||||
$this->assertEquals(4, $testVar3['score']);
|
||||
$this->assertEquals(4, $testVar4['score']);
|
||||
}
|
||||
// Passes: returns true
|
||||
$this->assertEquals(true, min_validation('test', 0));
|
||||
$this->assertEquals(true, min_validation('staple horse battery', 3));
|
||||
$this->assertEquals(true, min_validation('staple horse battery', 4));
|
||||
});
|
||||
|
||||
/** @test */
|
||||
public function test_password_strength()
|
||||
{
|
||||
// Standard tests
|
||||
$this->assertEquals(true, $this->validate_without_message_min('test', 0));
|
||||
$this->assertEquals(false, $this->validate_without_message_min('test', 4));
|
||||
it('can validate dictionary-rule', function () {
|
||||
// Fails: returns message
|
||||
$this->assertEquals('The password is too simililar to another field.', dictionary_validation('dadaurka', 'test@test.com', 'dadaurka', null));
|
||||
$this->assertEquals('The password is too simililar to another field.', dictionary_validation('dadaurka', 'dadaurka', null, null));
|
||||
$this->assertEquals('Just a message', dictionary_validation('test', 'test@test.com', 'test', 'Just a message'));
|
||||
|
||||
$this->assertEquals(true, $this->validate_without_message_min('staple horse battery', 3));
|
||||
$this->assertEquals(true, $this->validate_without_message_min('staple horse battery', 4));
|
||||
$this->assertEquals(false, $this->validate_without_message_min('staple horse battery', 5));
|
||||
}
|
||||
// Passes: returns true
|
||||
$this->assertEquals(true, dictionary_validation('d5=:r+AEl5?+', 'dadaurka@test.com', 'dadaurka', null));
|
||||
$this->assertEquals(true, dictionary_validation('Mo]R^v@vYo]I', 'myemail@test.com', 'username', null));
|
||||
$this->assertEquals(true, dictionary_validation('%!/%^Qz1q&KH', 'trash@thedumpster.com', 'username', null));
|
||||
$this->assertEquals(true, dictionary_validation('O`l}/RqR9$.S','trash@thedumpster.com', null, null));
|
||||
});
|
||||
|
||||
/** @test */
|
||||
public function test_password_strength_with_message()
|
||||
{
|
||||
// Standard message
|
||||
$this->assertEquals('Your password is not secure enough.', $this->validate_with_message_min('staple horse battery', 5, null));
|
||||
$this->assertEquals('Just a message', $this->validate_with_message_min('test', 4, 'Just a message'));
|
||||
}
|
||||
it('can validate rules as objects', function() {
|
||||
// Pass min-rule, fail dictionary-rule
|
||||
$this->assertEquals('The password is too simililar to another field.', rule_validator(3, 'gagadododaka', 'gagadododaka@test.com', 'gagadododaka', null));
|
||||
|
||||
/** @test */
|
||||
public function test_password_dictionary()
|
||||
{
|
||||
// Standard tests
|
||||
$this->assertEquals(false, $this->validate_without_message_dictionary('password', 'test@test.com', 'test'));
|
||||
$this->assertEquals(false, $this->validate_without_message_dictionary('test', 'test@test.com', 'test'));
|
||||
$this->assertEquals(false, $this->validate_without_message_dictionary('721ahsa!', '721ahsa@test.com', '721ahsa'));
|
||||
// Fail min-rule, pass dictionary-rule
|
||||
$this->assertEquals('The password is not strong enough.', rule_validator(4, 'test', 'trash@thedumpster.com', 'username', null));
|
||||
|
||||
$this->assertEquals(true, $this->validate_without_message_dictionary('721ahsa!', 'dadaurka@test.com', 'dadaurka'));
|
||||
$this->assertEquals(true, $this->validate_without_message_dictionary('asd912j!', 'myemail@test.com', 'username'));
|
||||
$this->assertEquals(true, $this->validate_without_message_dictionary('asd912j!', 'trash@thedumpster.com', 'username'));
|
||||
// Pass both rules
|
||||
$this->assertEquals('The password is not strong enough.', rule_validator(7, 'O`l}/RqR9$.S', 'trash@thedumpster.com', null));
|
||||
});
|
||||
|
||||
$this->assertEquals(true, $this->validate_without_message_dictionary('asd912j!', null, 'username'));
|
||||
$this->assertEquals(true, $this->validate_without_message_dictionary('asd912j!', null, null));
|
||||
}
|
||||
/** @note validation helper */
|
||||
function min_validation($password, $min, $message = null)
|
||||
{
|
||||
$data = ['password' => $password];
|
||||
$validator = Validator::make($data, [
|
||||
'password' => ['required', 'zxcvbn:' . $min],
|
||||
], $message ? ['password.zxcvbn' => $message] : []);
|
||||
|
||||
/** @test */
|
||||
public function test_password_dictionary_with_message()
|
||||
{
|
||||
// Standard message
|
||||
$this->assertEquals('Your password is insecure. It either matches a commonly used password, or you have used a similar username/password combination.', $this->validate_with_message_dictionary('password', 'test@test.com', 'test', null));
|
||||
$this->assertEquals('Just a message', $this->validate_with_message_dictionary('test', 'test@test.com', 'test', 'Just a message'));
|
||||
}
|
||||
|
||||
/** @note validation helper */
|
||||
private function validate_without_message_min($password, $min)
|
||||
{
|
||||
$data = ['password' => $password];
|
||||
$validator = Validator::make($data, [
|
||||
'password' => 'zxcvbn_min:' . $min . '|required',
|
||||
]);
|
||||
|
||||
return $validator->passes();
|
||||
}
|
||||
|
||||
/** @note validation helper */
|
||||
private function validate_with_message_min($password, $min, $message)
|
||||
{
|
||||
$data = ['password' => $password];
|
||||
$validator = Validator::make($data, [
|
||||
'password' => 'zxcvbn_min:' . $min . '|required',
|
||||
], [
|
||||
'password.zxcvbn_min' => $message
|
||||
]);
|
||||
|
||||
$errors = $validator->errors();
|
||||
if (!$validator->passes()) {
|
||||
$errors = $validator->errors('password');
|
||||
return $errors->first('password');
|
||||
}
|
||||
}
|
||||
|
||||
/** @note validation helper */
|
||||
private function validate_without_message_dictionary($password, $email, $username)
|
||||
{
|
||||
$data = ['password' => $password];
|
||||
$validator = Validator::make($data, [
|
||||
'password' => 'zxcvbn_dictionary:' . $username . ',' . $email . '|required',
|
||||
]);
|
||||
|
||||
return $validator->passes();
|
||||
}
|
||||
|
||||
/** @note validation helper */
|
||||
private function validate_with_message_dictionary($password, $email, $username, $message)
|
||||
{
|
||||
$data = ['password' => $password];
|
||||
$validator = Validator::make($data, [
|
||||
'password' => 'zxcvbn_dictionary:' . $username . ',' . $email . '|required',
|
||||
], [
|
||||
'password.zxcvbn_dictionary' => $message
|
||||
]);
|
||||
|
||||
$errors = $validator->errors();
|
||||
return $errors->first('password');
|
||||
}
|
||||
return $validator->passes();
|
||||
}
|
||||
|
||||
/** @note validation helper */
|
||||
function dictionary_validation($password, $email, $username, $message = null)
|
||||
{
|
||||
$data = ['password' => $password];
|
||||
$validator = Validator::make($data, [
|
||||
'password' => 'zxcvbn_dictionary:' . $username . ',' . $email . '|required',
|
||||
], $message ? ['password.zxcvbn_dictionary' => $message] : []);
|
||||
|
||||
if (!$validator->passes()) {
|
||||
$errors = $validator->errors('password');
|
||||
return $errors->first('password');
|
||||
}
|
||||
|
||||
return $validator->passes();
|
||||
}
|
||||
|
||||
/** @note object rule validator */
|
||||
function rule_validator($min, $password, $email, $username, $message = null)
|
||||
{
|
||||
$data = ['password' => $password];
|
||||
$validator = Validator::make($data, [
|
||||
'password' => ['required', new ZxcvbnDictionaryRule($username, $email), new ZxcvbnRule($min)],
|
||||
], $message ? ['password.zxcvbn' => $message] : []);
|
||||
|
||||
if (!$validator->passes()) {
|
||||
$errors = $validator->errors('password');
|
||||
return $errors->first('password');
|
||||
}
|
||||
|
||||
return $validator->passes();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue