Initial commit.
This commit is contained in:
commit
768720a83a
|
|
@ -0,0 +1,15 @@
|
|||
; This file is for unifying the coding style for different editors and IDEs.
|
||||
; More information at http://editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
/vendor
|
||||
composer.lock
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
language: php
|
||||
php:
|
||||
- 5.5
|
||||
- 5.6
|
||||
- 7.0
|
||||
- nightly
|
||||
|
||||
before_script: composer install
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
# The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Marcus Olsson <hello@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
|
||||
> in the Software without restriction, including without limitation the rights
|
||||
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
> copies of the Software, and to permit persons to whom the Software is
|
||||
> furnished to do so, subject to the following conditions:
|
||||
>
|
||||
> The above copyright notice and this permission notice shall be included in
|
||||
> all copies or substantial portions of the Software.
|
||||
>
|
||||
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
> THE SOFTWARE.
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
# Zxcvbn for Laravel 5
|
||||
|
||||
[![Latest Version on Packagist][ico-version]][link-packagist]
|
||||
[![Software License][ico-license]](LICENSE.md)
|
||||
[![Build Status][ico-travis]][link-travis]
|
||||
|
||||
A simple implementation of zxcvbn for Laravel 5. This package allows you to access "zxcvbn-related" data on a passphrase in the application, but also use zxcvbn as a standard validator.
|
||||
|
||||
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
|
||||
|
||||
Via Composer
|
||||
|
||||
``` bash
|
||||
$ composer require olssonm/l5-zxcvbn
|
||||
```
|
||||
|
||||
Add the package to your providers array:
|
||||
|
||||
``` php
|
||||
'providers' => [
|
||||
Olssonm\Zxcvbn\ZxcvbnServiceProvider::class,
|
||||
]
|
||||
```
|
||||
|
||||
If you wish to have the ability to use `Zxcvbn` via dependency injection, or just have a quick way to access the class – add an alias to the facades:
|
||||
|
||||
``` php
|
||||
'aliases' => [
|
||||
'Zxcvbn' => Olssonm\Zxcvbn\Facades\Zxcvbn::class
|
||||
]
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
If you've added `Olssonm\Zxcvbn` as an alias, your can access Zxcvbn easily from anywhere in your application:
|
||||
|
||||
### "In app"
|
||||
|
||||
``` php
|
||||
<?php
|
||||
use Zxcvbn;
|
||||
|
||||
class MyClass
|
||||
{
|
||||
public function myFunction()
|
||||
{
|
||||
$zxcvbn = Zxcvbn::passwordStrength('password');;
|
||||
dd($zxcvbn->passwordStrength('password'));
|
||||
|
||||
// array:6 [
|
||||
// "crack_time" => 5.0E-5
|
||||
// "calc_time" => 0.1857271194458
|
||||
// "password" => "password"
|
||||
// "entropy" => 0.0
|
||||
// "match_sequence" => array:1 []
|
||||
// "score" => 0
|
||||
// ]
|
||||
}
|
||||
}
|
||||
?>
|
||||
```
|
||||
|
||||
Play around with different passwords and phrases, the results may surprise you. Check out [Zxcvbn-PHP](https://github.com/bjeavons/zxcvbn-php) for more uses and examples.
|
||||
|
||||
### As a validator
|
||||
|
||||
The package gives you two different validation rules that you may use; `zxcvbn_min` and `zxcvbn_dictionary`.
|
||||
|
||||
#### zxcvbn_min
|
||||
|
||||
`zxcvbn_min` allows you to set up a rule for minimum score that the value beeing tested should adhere to.
|
||||
|
||||
***Syntax***
|
||||
`'input' => 'zxcvbn_min:min_value'`
|
||||
|
||||
``` php
|
||||
<?php
|
||||
$data = ['password' => 'password'];
|
||||
$validator = Validator::make($data, [
|
||||
'password' => 'zxcvbn_min:3|required',
|
||||
], [
|
||||
'password.zxcvbn_min' => 'Your password is not strong enough!'
|
||||
]);
|
||||
```
|
||||
|
||||
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...
|
||||
|
||||
#### zxcvbn_dictionary
|
||||
|
||||
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.
|
||||
|
||||
***Syntax***
|
||||
`'input' => 'xcvbn_dictionary:username,email'`
|
||||
|
||||
``` php
|
||||
<?php
|
||||
/**
|
||||
* Example 1, pass
|
||||
*/
|
||||
$password = '31??2sa//"dhjd2askjd19sad19!!&!#"';
|
||||
$data = [
|
||||
'username' => 'user',
|
||||
'email' => 'trash@thedumpster.com'
|
||||
];
|
||||
$validator = Validator::make($password, [
|
||||
'password' => 'zxcvbn_dictionary:' . $data['username'] . ',' . $data['email'] . '|required',
|
||||
]);
|
||||
|
||||
dd($validator->passes());
|
||||
// true
|
||||
|
||||
/**
|
||||
* Example 2, fail
|
||||
*/
|
||||
$password = 'mycomplicatedphrase';
|
||||
$data = [
|
||||
'username' => 'mycomplicatedphrase',
|
||||
'email' => 'mycomplicatedphrase@thedumpster.com'
|
||||
];
|
||||
$validator = Validator::make($password, [
|
||||
'password' => 'zxcvbn_dictionary:' . $data['username'] . ',' . $data['email'] . '|required',
|
||||
]);
|
||||
|
||||
dd($validator->passes());
|
||||
// false
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
``` bash
|
||||
$ composer test
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
``` bash
|
||||
$ phpunit
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
|
||||
|
||||
© 2015 [Marcus Olsson](https://marcusolsson.me).
|
||||
|
||||
[ico-version]: https://img.shields.io/packagist/v/olssonm/l5-zxcvbn.svg?style=flat-square
|
||||
[ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square
|
||||
[ico-travis]: https://img.shields.io/travis/olssonm/l5-zxcvbn/master.svg?style=flat-square
|
||||
[link-packagist]: https://packagist.org/packages/olssonm/l5-zxcvbn
|
||||
[link-travis]: https://travis-ci.org/olssonm/l5-zxcvbn
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
{
|
||||
"name": "olssonm/l5-zxcvbn",
|
||||
"description": "Implementation of the zxcvbn project by @dropbox for Laravel 5. Uses zxcvbn-php by @bjeavons.",
|
||||
"keywords": [
|
||||
"olssonm",
|
||||
"zxcvbn",
|
||||
"staple horse battery",
|
||||
"passwords",
|
||||
"validation",
|
||||
"laravel"
|
||||
],
|
||||
"homepage": "https://github.com/olssonm/l5-zxcvbn",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Marcus Olsson",
|
||||
"email": "hello@marcusolsson.me",
|
||||
"homepage": "https://marcusolsson.me"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php" : ">=5.3.0",
|
||||
"illuminate/support": "~5.1",
|
||||
"bjeavons/zxcvbn-php": "0.1.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit" : "4.*",
|
||||
"orchestra/testbench": "~3.0",
|
||||
"scrutinizer/ocular": "~1.1"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Olssonm\\Zxcvbn\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Olssonm\\Zxcvbn\\Test\\": "tests/"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": "phpunit"
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.x-dev"
|
||||
}
|
||||
},
|
||||
"minimum-stability": "stable"
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
bootstrap="vendor/autoload.php"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false"
|
||||
syntaxCheck="false"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="Package Test Suite">
|
||||
<directory suffix=".php">./tests/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace Olssonm\Zxcvbn\Facades;
|
||||
|
||||
use Illuminate\Support\Facades\Facade;
|
||||
|
||||
class Zxcvbn extends Facade
|
||||
{
|
||||
/**
|
||||
* Get the registered name of the component.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function getFacadeAccessor()
|
||||
{
|
||||
return 'zxcvbn';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
namespace Olssonm\Zxcvbn;
|
||||
|
||||
use ZxcvbnPhp\Zxcvbn as ZxcvbnPhp;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Validator;
|
||||
|
||||
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, $validator) {
|
||||
$zxcvbn = new ZxcvbnPhp();
|
||||
$zxcvbn = $zxcvbn->passwordStrength($value);
|
||||
$target = 5;
|
||||
|
||||
if(isset($parameters[0])) {
|
||||
$target = $parameters[0];
|
||||
}
|
||||
|
||||
return ($zxcvbn['score'] >= $target);
|
||||
}, 'Your :input is not secure enough.');
|
||||
|
||||
Validator::replacer('zxcvbn_min', function($message, $attribute, $rule, $parameters) {
|
||||
$message = str_replace(':input', $attribute, $message);
|
||||
return $message;
|
||||
});
|
||||
|
||||
/**
|
||||
* Extend the Laravel Validator with the "zxcvbn_min" rule
|
||||
*/
|
||||
Validator::extend('zxcvbn_dictionary', function($attribute, $value, $parameters, $validator) {
|
||||
$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['match_sequence'][0])) {
|
||||
$dictionary = $zxcvbn['match_sequence'][0];
|
||||
if(isset($dictionary->dictionaryName)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}, 'Your :input 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, $rule, $parameters) {
|
||||
$message = str_replace(':input', $attribute, $message);
|
||||
return $message;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register any package services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
$this->app['zxcvbn'] = $this->app->share(function ($app) {
|
||||
return new ZxcvbnPhp($this->app['config']);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
<?php namespace Olssonm\Zxcvbn\Tests;
|
||||
|
||||
use Validator;
|
||||
|
||||
use Zxcvbn;
|
||||
|
||||
class ZxcvbnTest extends \Orchestra\Testbench\TestCase {
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the package
|
||||
* @return array the packages
|
||||
*/
|
||||
protected function getPackageProviders($app)
|
||||
{
|
||||
return [
|
||||
'Olssonm\Zxcvbn\ZxcvbnServiceProvider'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the alias
|
||||
* @return array the aliases
|
||||
*/
|
||||
protected function getPackageAliases($app)
|
||||
{
|
||||
return [
|
||||
'Zxcvbn' => 'Olssonm\Zxcvbn\Facades\Zxcvbn'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Just run som standard tests to see that Zxcvbn is up to snuff and working
|
||||
* @test
|
||||
*/
|
||||
public function test_zxcvbn_basics()
|
||||
{
|
||||
$testVar1 = Zxcvbn::passwordStrength('test');
|
||||
|
||||
// Check keys
|
||||
$this->assertArrayHasKey('score', $testVar1);
|
||||
$this->assertArrayHasKey('match_sequence', $testVar1);
|
||||
$this->assertArrayHasKey('entropy', $testVar1);
|
||||
$this->assertArrayHasKey('password', $testVar1);
|
||||
$this->assertArrayHasKey('calc_time', $testVar1);
|
||||
$this->assertArrayHasKey('crack_time', $testVar1);
|
||||
|
||||
// Check score-value
|
||||
$this->assertEquals(0, $testVar1['score']);
|
||||
|
||||
// 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(1, $testVar2['score']);
|
||||
$this->assertEquals(4, $testVar3['score']);
|
||||
$this->assertEquals(4, $testVar4['score']);
|
||||
}
|
||||
|
||||
/** @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));
|
||||
|
||||
$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));
|
||||
}
|
||||
|
||||
/** @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'));
|
||||
}
|
||||
|
||||
/** @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'));
|
||||
|
||||
$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'));
|
||||
|
||||
$this->assertEquals(true, $this->validate_without_message_dictionary('asd912j!', null, 'username'));
|
||||
$this->assertEquals(true, $this->validate_without_message_dictionary('asd912j!', null, null));
|
||||
}
|
||||
|
||||
/** @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'));
|
||||
}
|
||||
|
||||
private function validate_without_message_min($password, $min)
|
||||
{
|
||||
$data = ['password' => $password];
|
||||
$validator = Validator::make($data, [
|
||||
'password' => 'zxcvbn_min:' . $min . '|required',
|
||||
]);
|
||||
|
||||
return $validator->passes();
|
||||
}
|
||||
|
||||
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();
|
||||
return $errors->first('password');
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue