mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-08 12:12:48 +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)
|
||||
{
|
||||
return view('auth.passwords.reset')->with(
|
||||
['token' => $token]
|
||||
);
|
||||
return view('auth.passwords.reset')->with([
|
||||
'token' => $token,
|
||||
'url' => '/password/reset'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -54,9 +54,10 @@ class ResetPasswordController extends Controller
|
||||
|
||||
public function showResetForm(Request $request, $token = null)
|
||||
{
|
||||
return view('clientauth.passwords.reset')->with(
|
||||
['token' => $token]
|
||||
);
|
||||
return view('auth.passwords.reset')->with([
|
||||
'token' => $token,
|
||||
'url' => '/client/password/reset'
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ class Authenticate
|
||||
} else {
|
||||
if ($guard == 'client') {
|
||||
$url = '/client/login';
|
||||
if (Utils::isNinja()) {
|
||||
if (Utils::isNinjaProd()) {
|
||||
if ($account && Utils::getSubdomain() == 'app') {
|
||||
$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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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',
|
||||
'autofills_city_state' => 'Auto-fills city/state',
|
||||
'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('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/>
|
||||
@ -205,7 +205,7 @@
|
||||
var isValid = val;
|
||||
|
||||
if (field != 'current_password') {
|
||||
isValid = val.length >= 6;
|
||||
isValid = val.length >= 8;
|
||||
}
|
||||
|
||||
if (isValid && field == 'confirm_password') {
|
||||
@ -221,6 +221,15 @@
|
||||
$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);
|
||||
|
@ -3,10 +3,11 @@
|
||||
@section('form')
|
||||
<div class="container">
|
||||
|
||||
{!! Former::open('/password/reset')
|
||||
{!! Former::open($url)
|
||||
->addClass('form-signin')
|
||||
->autocomplete('off')
|
||||
->rules(array(
|
||||
'email' => 'required|email',
|
||||
'password' => 'required',
|
||||
'password_confirmation' => 'required',
|
||||
)) !!}
|
||||
@ -39,13 +40,17 @@
|
||||
|
||||
<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::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>
|
||||
<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() !!}
|
||||
@ -53,7 +58,32 @@
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
$('#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>
|
||||
|
||||
@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 */
|
||||
$.extend(true, $.fn.dataTable.defaults, {
|
||||
"bSortClasses": false,
|
||||
|
@ -1,53 +1,53 @@
|
||||
<script type="text/javascript">
|
||||
|
||||
$(function() {
|
||||
$(function() {
|
||||
|
||||
validateSignUp();
|
||||
validateSignUp();
|
||||
|
||||
$('#signUpModal').on('shown.bs.modal', function () {
|
||||
$('#signUpModal').on('shown.bs.modal', function () {
|
||||
trackEvent('/account', '/view_sign_up');
|
||||
// change the type after page load to prevent errors in Chrome console
|
||||
$('#new_password').attr('type', 'password');
|
||||
$(['first_name','last_name','email','password']).each(function(i, field) {
|
||||
var $input = $('form.signUpForm #new_'+field);
|
||||
if (!$input.val()) {
|
||||
$input.focus();
|
||||
return false;
|
||||
}
|
||||
var $input = $('form.signUpForm #new_'+field);
|
||||
if (!$input.val()) {
|
||||
$input.focus();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
@if (Auth::check() && !Utils::isNinja() && ! Auth::user()->registered)
|
||||
$('#closeSignUpButton').hide();
|
||||
showSignUp();
|
||||
@elseif(Session::get('sign_up') || Input::get('sign_up'))
|
||||
showSignUp();
|
||||
@endif
|
||||
@if (Auth::check() && !Utils::isNinja() && ! Auth::user()->registered)
|
||||
$('#closeSignUpButton').hide();
|
||||
showSignUp();
|
||||
@elseif(Session::get('sign_up') || Input::get('sign_up'))
|
||||
showSignUp();
|
||||
@endif
|
||||
|
||||
// Ensure terms is checked for sign up form
|
||||
@if (Auth::check())
|
||||
setSignupEnabled(false);
|
||||
$("#terms_checkbox").change(function() {
|
||||
setSignupEnabled(this.checked);
|
||||
});
|
||||
@endif
|
||||
// Ensure terms is checked for sign up form
|
||||
@if (Auth::check())
|
||||
setSignupEnabled(false);
|
||||
$("#terms_checkbox").change(function() {
|
||||
setSignupEnabled(this.checked);
|
||||
});
|
||||
@endif
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
function showSignUp() {
|
||||
function showSignUp() {
|
||||
if (location.href.indexOf('/dashboard') == -1) {
|
||||
location.href = "{{ url('/dashboard') }}?sign_up=true";
|
||||
} else {
|
||||
$('#signUpModal').modal('show');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function hideSignUp() {
|
||||
function hideSignUp() {
|
||||
$('#signUpModal').modal('hide');
|
||||
}
|
||||
}
|
||||
|
||||
function setSignupEnabled(enabled) {
|
||||
function setSignupEnabled(enabled) {
|
||||
$('.signup-form input[type=text]').prop('disabled', !enabled);
|
||||
$('.signup-form input[type=password]').prop('disabled', !enabled);
|
||||
if (enabled) {
|
||||
@ -55,100 +55,108 @@
|
||||
} else {
|
||||
$('.signup-form a.btn').addClass('disabled');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function validateSignUp(showError)
|
||||
{
|
||||
function validateSignUp(showError) {
|
||||
var isFormValid = true;
|
||||
$(['first_name','last_name','email','password']).each(function(i, field) {
|
||||
var $input = $('form.signUpForm #new_'+field),
|
||||
val = $.trim($input.val());
|
||||
var isValid = val && val.length >= (field == 'password' ? 6 : 1);
|
||||
if (isValid && field == 'email') {
|
||||
isValid = isValidEmailAddress(val);
|
||||
}
|
||||
if (isValid) {
|
||||
$input.closest('div.form-group').removeClass('has-error').addClass('has-success');
|
||||
} else {
|
||||
isFormValid = false;
|
||||
$input.closest('div.form-group').removeClass('has-success');
|
||||
if (showError) {
|
||||
$input.closest('div.form-group').addClass('has-error');
|
||||
var $input = $('form.signUpForm #new_'+field),
|
||||
val = $.trim($input.val());
|
||||
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') {
|
||||
isValid = isValidEmailAddress(val);
|
||||
}
|
||||
if (isValid) {
|
||||
$input.closest('div.form-group').removeClass('has-error').addClass('has-success');
|
||||
} else {
|
||||
isFormValid = false;
|
||||
$input.closest('div.form-group').removeClass('has-success');
|
||||
if (showError) {
|
||||
$input.closest('div.form-group').addClass('has-error');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!$('#terms_checkbox').is(':checked')) {
|
||||
isFormValid = false;
|
||||
isFormValid = false;
|
||||
}
|
||||
|
||||
$('#saveSignUpButton').prop('disabled', !isFormValid);
|
||||
|
||||
return isFormValid;
|
||||
}
|
||||
}
|
||||
|
||||
function validateServerSignUp()
|
||||
{
|
||||
function validateServerSignUp() {
|
||||
if (!validateSignUp(true)) {
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
$('#signUpDiv, #signUpFooter').hide();
|
||||
$('#working').show();
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: '{{ URL::to('signup/validate') }}',
|
||||
data: 'email=' + $('form.signUpForm #new_email').val(),
|
||||
success: function(result) {
|
||||
if (result == 'available') {
|
||||
submitSignUp();
|
||||
} else {
|
||||
$('#errorTaken').show();
|
||||
$('form.signUpForm #new_email').closest('div.form-group').removeClass('has-success').addClass('has-error');
|
||||
$('#signUpDiv, #signUpFooter').show();
|
||||
$('#working').hide();
|
||||
type: 'POST',
|
||||
url: '{{ URL::to('signup/validate') }}',
|
||||
data: 'email=' + $('form.signUpForm #new_email').val(),
|
||||
success: function(result) {
|
||||
if (result == 'available') {
|
||||
submitSignUp();
|
||||
} else {
|
||||
$('#errorTaken').show();
|
||||
$('form.signUpForm #new_email').closest('div.form-group').removeClass('has-success').addClass('has-error');
|
||||
$('#signUpDiv, #signUpFooter').show();
|
||||
$('#working').hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function submitSignUp() {
|
||||
function submitSignUp() {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: '{{ URL::to('signup/submit') }}',
|
||||
data: 'new_email=' + encodeURIComponent($('form.signUpForm #new_email').val()) +
|
||||
'&new_password=' + encodeURIComponent($('form.signUpForm #new_password').val()) +
|
||||
'&new_first_name=' + encodeURIComponent($('form.signUpForm #new_first_name').val()) +
|
||||
'&new_last_name=' + encodeURIComponent($('form.signUpForm #new_last_name').val()) +
|
||||
'&go_pro=' + $('#go_pro').val(),
|
||||
success: function(result) {
|
||||
if (result) {
|
||||
@if (Auth::user()->registered)
|
||||
hideSignUp();
|
||||
NINJA.formIsChanged = false;
|
||||
location.href = "{{ url('/dashboard') }}";
|
||||
@else
|
||||
handleSignedUp();
|
||||
NINJA.isRegistered = true;
|
||||
$('#gettingStartedIframe').attr('src', '{{ str_replace('watch?v=', 'embed/', config('ninja.video_urls.getting_started')) }}');
|
||||
$('#signUpButton').hide();
|
||||
$('#myAccountButton').html(result);
|
||||
$('#signUpSuccessDiv, #signUpFooter, #closeSignUpButton').show();
|
||||
$('#working, #saveSignUpButton').hide();
|
||||
@endif
|
||||
type: 'POST',
|
||||
url: '{{ URL::to('signup/submit') }}',
|
||||
data: 'new_email=' + encodeURIComponent($('form.signUpForm #new_email').val()) +
|
||||
'&new_password=' + encodeURIComponent($('form.signUpForm #new_password').val()) +
|
||||
'&new_first_name=' + encodeURIComponent($('form.signUpForm #new_first_name').val()) +
|
||||
'&new_last_name=' + encodeURIComponent($('form.signUpForm #new_last_name').val()) +
|
||||
'&go_pro=' + $('#go_pro').val(),
|
||||
success: function(result) {
|
||||
if (result) {
|
||||
@if (Auth::user()->registered)
|
||||
hideSignUp();
|
||||
NINJA.formIsChanged = false;
|
||||
location.href = "{{ url('/dashboard') }}";
|
||||
@else
|
||||
handleSignedUp();
|
||||
NINJA.isRegistered = true;
|
||||
$('#gettingStartedIframe').attr('src', '{{ str_replace('watch?v=', 'embed/', config('ninja.video_urls.getting_started')) }}');
|
||||
$('#signUpButton').hide();
|
||||
$('#myAccountButton').html(result);
|
||||
$('#signUpSuccessDiv, #signUpFooter, #closeSignUpButton').show();
|
||||
$('#working, #saveSignUpButton').hide();
|
||||
@endif
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handleSignedUp() {
|
||||
if (isStorageSupported()) {
|
||||
localStorage.setItem('guest_key', '');
|
||||
}
|
||||
fbq('track', 'CompleteRegistration');
|
||||
trackEvent('/account', '/signed_up');
|
||||
}
|
||||
function handleSignedUp() {
|
||||
if (isStorageSupported()) {
|
||||
localStorage.setItem('guest_key', '');
|
||||
}
|
||||
fbq('track', 'CompleteRegistration');
|
||||
trackEvent('/account', '/signed_up');
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
@ -234,7 +242,8 @@
|
||||
->placeholder(trans('texts.password'))
|
||||
->autocomplete('new-password')
|
||||
->data_lpignore('true')
|
||||
->label(' ') !!}
|
||||
->label(' ')
|
||||
->help('<span id="passwordStrength"> </span>') !!}
|
||||
|
||||
{{ Former::setOption('TwitterBootstrap3.labelWidths.large', 4) }}
|
||||
{{ Former::setOption('TwitterBootstrap3.labelWidths.small', 4) }}
|
||||
|
Loading…
Reference in New Issue
Block a user