mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-08 20:22:42 +01:00
Added password strength check
This commit is contained in:
parent
a09ba934cf
commit
d0d510331a
@ -58,8 +58,9 @@ class ResetPasswordController extends Controller
|
|||||||
|
|
||||||
public function showResetForm(Request $request, $token = null)
|
public function showResetForm(Request $request, $token = null)
|
||||||
{
|
{
|
||||||
return view('auth.passwords.reset')->with(
|
return view('auth.passwords.reset')->with([
|
||||||
['token' => $token]
|
'token' => $token,
|
||||||
);
|
'url' => '/password/reset'
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,9 +54,10 @@ class ResetPasswordController extends Controller
|
|||||||
|
|
||||||
public function showResetForm(Request $request, $token = null)
|
public function showResetForm(Request $request, $token = null)
|
||||||
{
|
{
|
||||||
return view('clientauth.passwords.reset')->with(
|
return view('auth.passwords.reset')->with([
|
||||||
['token' => $token]
|
'token' => $token,
|
||||||
);
|
'url' => '/client/password/reset'
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,7 @@ class Authenticate
|
|||||||
} else {
|
} else {
|
||||||
if ($guard == 'client') {
|
if ($guard == 'client') {
|
||||||
$url = '/client/login';
|
$url = '/client/login';
|
||||||
if (Utils::isNinja()) {
|
if (Utils::isNinjaProd()) {
|
||||||
if ($account && Utils::getSubdomain() == 'app') {
|
if ($account && Utils::getSubdomain() == 'app') {
|
||||||
$url .= '?account_key=' . $account->account_key;
|
$url .= '?account_key=' . $account->account_key;
|
||||||
}
|
}
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1265,3 +1265,33 @@ function openUrlOnClick(url, event) {
|
|||||||
window.location = url;
|
window.location = url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://stackoverflow.com/a/11268104/497368
|
||||||
|
function scorePassword(pass) {
|
||||||
|
var score = 0;
|
||||||
|
if (!pass)
|
||||||
|
return score;
|
||||||
|
|
||||||
|
// award every unique letter until 5 repetitions
|
||||||
|
var letters = new Object();
|
||||||
|
for (var i=0; i<pass.length; i++) {
|
||||||
|
letters[pass[i]] = (letters[pass[i]] || 0) + 1;
|
||||||
|
score += 5.0 / letters[pass[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
// bonus points for mixing it up
|
||||||
|
var variations = {
|
||||||
|
digits: /\d/.test(pass),
|
||||||
|
lower: /[a-z]/.test(pass),
|
||||||
|
upper: /[A-Z]/.test(pass),
|
||||||
|
nonWords: /\W/.test(pass),
|
||||||
|
}
|
||||||
|
|
||||||
|
variationCount = 0;
|
||||||
|
for (var check in variations) {
|
||||||
|
variationCount += (variations[check] == true) ? 1 : 0;
|
||||||
|
}
|
||||||
|
score += (variationCount - 1) * 10;
|
||||||
|
|
||||||
|
return parseInt(score);
|
||||||
|
}
|
||||||
|
@ -2825,6 +2825,10 @@ $LANG = array(
|
|||||||
'unapproved_proposal' => 'Unapproved Proposal',
|
'unapproved_proposal' => 'Unapproved Proposal',
|
||||||
'autofills_city_state' => 'Auto-fills city/state',
|
'autofills_city_state' => 'Auto-fills city/state',
|
||||||
'no_match_found' => 'No match found',
|
'no_match_found' => 'No match found',
|
||||||
|
'password_strength' => 'Password Strength',
|
||||||
|
'strength_weak' => 'Weak',
|
||||||
|
'strength_good' => 'Good',
|
||||||
|
'strength_strong' => 'Strong',
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@
|
|||||||
|
|
||||||
{!! Former::password('current_password')->style('width:300px') !!}
|
{!! Former::password('current_password')->style('width:300px') !!}
|
||||||
{!! Former::password('newer_password')->style('width:300px')->label(trans('texts.new_password')) !!}
|
{!! Former::password('newer_password')->style('width:300px')->label(trans('texts.new_password')) !!}
|
||||||
{!! Former::password('confirm_password')->style('width:300px') !!}
|
{!! Former::password('confirm_password')->style('width:300px')->help('<span id="passwordStrength"> </span>') !!}
|
||||||
|
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
@ -205,7 +205,7 @@
|
|||||||
var isValid = val;
|
var isValid = val;
|
||||||
|
|
||||||
if (field != 'current_password') {
|
if (field != 'current_password') {
|
||||||
isValid = val.length >= 6;
|
isValid = val.length >= 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isValid && field == 'confirm_password') {
|
if (isValid && field == 'confirm_password') {
|
||||||
@ -221,6 +221,15 @@
|
|||||||
$input.closest('div.form-group').addClass('has-error');
|
$input.closest('div.form-group').addClass('has-error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (field == 'newer_password') {
|
||||||
|
var score = scorePassword(val);
|
||||||
|
if (isValid) {
|
||||||
|
isValid = score > 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
showPasswordStrength(val, score);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#changePasswordButton').prop('disabled', !isFormValid);
|
$('#changePasswordButton').prop('disabled', !isFormValid);
|
||||||
|
@ -3,10 +3,11 @@
|
|||||||
@section('form')
|
@section('form')
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|
||||||
{!! Former::open('/password/reset')
|
{!! Former::open($url)
|
||||||
->addClass('form-signin')
|
->addClass('form-signin')
|
||||||
->autocomplete('off')
|
->autocomplete('off')
|
||||||
->rules(array(
|
->rules(array(
|
||||||
|
'email' => 'required|email',
|
||||||
'password' => 'required',
|
'password' => 'required',
|
||||||
'password_confirmation' => 'required',
|
'password_confirmation' => 'required',
|
||||||
)) !!}
|
)) !!}
|
||||||
@ -39,13 +40,17 @@
|
|||||||
|
|
||||||
<input type="hidden" name="token" value="{{{ $token }}}">
|
<input type="hidden" name="token" value="{{{ $token }}}">
|
||||||
|
|
||||||
<div>
|
<div onkeyup="validateForm()" onclick="validateForm()" onkeydown="validateForm(event)">
|
||||||
{!! Former::text('email')->placeholder(trans('texts.email'))->raw() !!}
|
{!! Former::text('email')->placeholder(trans('texts.email'))->raw() !!}
|
||||||
{!! Former::password('password')->placeholder(trans('texts.password'))->autocomplete('new-password')->raw() !!}
|
{!! Former::password('password')->placeholder(trans('texts.password'))->autocomplete('new-password')->raw() !!}
|
||||||
{!! Former::password('password_confirmation')->placeholder(trans('texts.confirm_password'))->autocomplete('new-password')->raw() !!}
|
{!! Former::password('password_confirmation')->placeholder(trans('texts.confirm_password'))->autocomplete('new-password')->raw() !!}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p>{!! Button::success(trans('texts.save'))->large()->submit()->withAttributes(['class' => 'green'])->block() !!}</p>
|
<div id="passwordStrength" style="font-weight:normal;padding:16px">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>{!! Button::success(trans('texts.save'))->large()->submit()->withAttributes(['class' => 'green', 'id' => 'saveButton', 'disabled' => true])->block() !!}</p>
|
||||||
|
|
||||||
|
|
||||||
{!! Former::close() !!}
|
{!! Former::close() !!}
|
||||||
@ -53,7 +58,32 @@
|
|||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(function() {
|
$(function() {
|
||||||
$('#password').focus();
|
$('#password').focus();
|
||||||
|
validateForm();
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function validateForm() {
|
||||||
|
var isValid = true;
|
||||||
|
|
||||||
|
if (! $('#email').val()) {
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var password = $('#password').val();
|
||||||
|
var confirm = $('#password_confirmation').val();
|
||||||
|
|
||||||
|
if (! password || password != confirm || password.length < 8) {
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var score = scorePassword(password);
|
||||||
|
if (score < 50) {
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
showPasswordStrength(password, score);
|
||||||
|
|
||||||
|
$('#saveButton').prop('disabled', ! isValid);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@endsection
|
@endsection
|
||||||
|
@ -1,57 +0,0 @@
|
|||||||
@extends('login')
|
|
||||||
|
|
||||||
@section('form')
|
|
||||||
<div class="container">
|
|
||||||
|
|
||||||
{!! Former::open('/client/password/reset')
|
|
||||||
->addClass('form-signin')
|
|
||||||
->autocomplete('false')
|
|
||||||
->rules(array(
|
|
||||||
'password' => 'required',
|
|
||||||
'password_confirmation' => 'required',
|
|
||||||
)) !!}
|
|
||||||
|
|
||||||
@include('partials.autocomplete_fix')
|
|
||||||
|
|
||||||
<h2 class="form-signin-heading">{{ trans('texts.set_password') }}</h2>
|
|
||||||
<hr class="green">
|
|
||||||
|
|
||||||
@if (count($errors->all()))
|
|
||||||
<div class="alert alert-danger">
|
|
||||||
@foreach ($errors->all() as $error)
|
|
||||||
<li>{{ $error }}</li>
|
|
||||||
@endforeach
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
<!-- if there are login errors, show them here -->
|
|
||||||
@if (Session::has('warning'))
|
|
||||||
<div class="alert alert-warning">{{ Session::get('warning') }}</div>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
@if (Session::has('message'))
|
|
||||||
<div class="alert alert-info">{{ Session::get('message') }}</div>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
@if (Session::has('error'))
|
|
||||||
<div class="alert alert-danger">{{ Session::get('error') }}</div>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
<input type="hidden" name="token" value="{{{ $token }}}">
|
|
||||||
|
|
||||||
<div>
|
|
||||||
{!! Former::text('email')->placeholder(trans('texts.email'))->raw() !!}
|
|
||||||
{!! Former::password('password')->placeholder(trans('texts.password'))->autocomplete('new-password')->raw() !!}
|
|
||||||
{!! Former::password('password_confirmation')->placeholder(trans('texts.confirm_password'))->autocomplete('new-password')->raw() !!}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p>{!! Button::success(trans('texts.save'))->large()->submit()->withAttributes(['class' => 'green'])->block() !!}</p>
|
|
||||||
|
|
||||||
{!! Former::close() !!}
|
|
||||||
</div>
|
|
||||||
<script type="text/javascript">
|
|
||||||
$(function () {
|
|
||||||
$('#password').focus();
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
@endsection
|
|
@ -137,6 +137,22 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showPasswordStrength(password, score) {
|
||||||
|
if (password) {
|
||||||
|
var str = {!! json_encode(trans('texts.password_strength')) !!} + ': ';
|
||||||
|
if (password.length < 8 || score < 50) {
|
||||||
|
str += {!! json_encode(trans('texts.strength_weak')) !!};
|
||||||
|
} else if (score < 75) {
|
||||||
|
str += {!! json_encode(trans('texts.strength_good')) !!};
|
||||||
|
} else {
|
||||||
|
str += {!! json_encode(trans('texts.strength_strong')) !!};
|
||||||
|
}
|
||||||
|
$('#passwordStrength').html(str);
|
||||||
|
} else {
|
||||||
|
$('#passwordStrength').html(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Set the defaults for DataTables initialisation */
|
/* Set the defaults for DataTables initialisation */
|
||||||
$.extend(true, $.fn.dataTable.defaults, {
|
$.extend(true, $.fn.dataTable.defaults, {
|
||||||
"bSortClasses": false,
|
"bSortClasses": false,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
$(function() {
|
$(function() {
|
||||||
|
|
||||||
validateSignUp();
|
validateSignUp();
|
||||||
|
|
||||||
@ -32,22 +32,22 @@
|
|||||||
});
|
});
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
function showSignUp() {
|
function showSignUp() {
|
||||||
if (location.href.indexOf('/dashboard') == -1) {
|
if (location.href.indexOf('/dashboard') == -1) {
|
||||||
location.href = "{{ url('/dashboard') }}?sign_up=true";
|
location.href = "{{ url('/dashboard') }}?sign_up=true";
|
||||||
} else {
|
} else {
|
||||||
$('#signUpModal').modal('show');
|
$('#signUpModal').modal('show');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideSignUp() {
|
function hideSignUp() {
|
||||||
$('#signUpModal').modal('hide');
|
$('#signUpModal').modal('hide');
|
||||||
}
|
}
|
||||||
|
|
||||||
function setSignupEnabled(enabled) {
|
function setSignupEnabled(enabled) {
|
||||||
$('.signup-form input[type=text]').prop('disabled', !enabled);
|
$('.signup-form input[type=text]').prop('disabled', !enabled);
|
||||||
$('.signup-form input[type=password]').prop('disabled', !enabled);
|
$('.signup-form input[type=password]').prop('disabled', !enabled);
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
@ -55,15 +55,24 @@
|
|||||||
} else {
|
} else {
|
||||||
$('.signup-form a.btn').addClass('disabled');
|
$('.signup-form a.btn').addClass('disabled');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateSignUp(showError)
|
function validateSignUp(showError) {
|
||||||
{
|
|
||||||
var isFormValid = true;
|
var isFormValid = true;
|
||||||
$(['first_name','last_name','email','password']).each(function(i, field) {
|
$(['first_name','last_name','email','password']).each(function(i, field) {
|
||||||
var $input = $('form.signUpForm #new_'+field),
|
var $input = $('form.signUpForm #new_'+field),
|
||||||
val = $.trim($input.val());
|
val = $.trim($input.val());
|
||||||
var isValid = val && val.length >= (field == 'password' ? 6 : 1);
|
var isValid = val && val.length >= (field == 'password' ? 8 : 1);
|
||||||
|
|
||||||
|
if (field == 'password') {
|
||||||
|
var score = scorePassword(val);
|
||||||
|
if (isValid) {
|
||||||
|
isValid = score > 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
showPasswordStrength(val, score);
|
||||||
|
}
|
||||||
|
|
||||||
if (isValid && field == 'email') {
|
if (isValid && field == 'email') {
|
||||||
isValid = isValidEmailAddress(val);
|
isValid = isValidEmailAddress(val);
|
||||||
}
|
}
|
||||||
@ -85,10 +94,9 @@
|
|||||||
$('#saveSignUpButton').prop('disabled', !isFormValid);
|
$('#saveSignUpButton').prop('disabled', !isFormValid);
|
||||||
|
|
||||||
return isFormValid;
|
return isFormValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateServerSignUp()
|
function validateServerSignUp() {
|
||||||
{
|
|
||||||
if (!validateSignUp(true)) {
|
if (!validateSignUp(true)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -111,9 +119,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function submitSignUp() {
|
function submitSignUp() {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
url: '{{ URL::to('signup/submit') }}',
|
url: '{{ URL::to('signup/submit') }}',
|
||||||
@ -140,15 +148,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSignedUp() {
|
function handleSignedUp() {
|
||||||
if (isStorageSupported()) {
|
if (isStorageSupported()) {
|
||||||
localStorage.setItem('guest_key', '');
|
localStorage.setItem('guest_key', '');
|
||||||
}
|
}
|
||||||
fbq('track', 'CompleteRegistration');
|
fbq('track', 'CompleteRegistration');
|
||||||
trackEvent('/account', '/signed_up');
|
trackEvent('/account', '/signed_up');
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -234,7 +242,8 @@
|
|||||||
->placeholder(trans('texts.password'))
|
->placeholder(trans('texts.password'))
|
||||||
->autocomplete('new-password')
|
->autocomplete('new-password')
|
||||||
->data_lpignore('true')
|
->data_lpignore('true')
|
||||||
->label(' ') !!}
|
->label(' ')
|
||||||
|
->help('<span id="passwordStrength"> </span>') !!}
|
||||||
|
|
||||||
{{ Former::setOption('TwitterBootstrap3.labelWidths.large', 4) }}
|
{{ Former::setOption('TwitterBootstrap3.labelWidths.large', 4) }}
|
||||||
{{ Former::setOption('TwitterBootstrap3.labelWidths.small', 4) }}
|
{{ Former::setOption('TwitterBootstrap3.labelWidths.small', 4) }}
|
||||||
|
Loading…
Reference in New Issue
Block a user