Skip to content
This repository has been archived by the owner on Oct 1, 2021. It is now read-only.

Commit

Permalink
feature: password live validation & username compatibility tweaks (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
alfonsobries authored Oct 21, 2020
1 parent 2aae32a commit 9cf0748
Show file tree
Hide file tree
Showing 17 changed files with 439 additions and 137 deletions.
1 change: 1 addition & 0 deletions .php_cs.cache
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"php":"7.4.11","version":"2.16.4:v2.16.4#1023c3458137ab052f6ff1e09621a721bfdeca13","indent":" ","lineEnding":"\n","rules":{"array_syntax":{"syntax":"short"},"binary_operator_spaces":{"align_double_arrow":true,"align_equals":true},"blank_line_after_namespace":true,"blank_line_after_opening_tag":true,"blank_line_before_return":true,"blank_line_before_statement":true,"braces":true,"cast_spaces":true,"class_attributes_separation":true,"class_definition":true,"combine_consecutive_unsets":true,"concat_space":true,"declare_equal_normalize":true,"elseif":true,"encoding":true,"full_opening_tag":true,"fully_qualified_strict_types":true,"function_declaration":true,"function_typehint_space":true,"heredoc_to_nowdoc":true,"include":true,"increment_style":{"style":"post"},"indentation_type":true,"line_ending":true,"linebreak_after_opening_tag":true,"list_syntax":{"syntax":"short"},"lowercase_cast":true,"lowercase_constants":true,"lowercase_keywords":true,"lowercase_static_reference":true,"magic_constant_casing":true,"magic_method_casing":true,"method_argument_space":true,"method_separation":true,"multiline_whitespace_before_semicolons":true,"native_function_casing":true,"new_with_braces":true,"no_alias_functions":true,"no_blank_lines_after_class_opening":true,"no_blank_lines_after_phpdoc":true,"no_closing_tag":true,"no_empty_phpdoc":true,"no_empty_statement":true,"no_extra_blank_lines":true,"no_extra_consecutive_blank_lines":true,"no_leading_import_slash":true,"no_leading_namespace_whitespace":true,"no_mixed_echo_print":true,"no_multiline_whitespace_around_double_arrow":true,"no_multiline_whitespace_before_semicolons":true,"no_short_bool_cast":true,"no_short_echo_tag":true,"no_singleline_whitespace_before_semicolons":true,"no_spaces_after_function_name":true,"no_spaces_around_offset":true,"no_spaces_inside_parenthesis":true,"no_trailing_comma_in_list_call":true,"no_trailing_comma_in_singleline_array":true,"no_trailing_whitespace_in_comment":true,"no_trailing_whitespace":true,"no_unneeded_control_parentheses":true,"no_unreachable_default_argument_value":true,"no_unused_imports":true,"no_useless_else":true,"no_useless_return":true,"no_whitespace_before_comma_in_array":true,"no_whitespace_in_blank_line":true,"normalize_index_brace":true,"not_operator_with_successor_space":true,"object_operator_without_whitespace":true,"ordered_imports":{"sortAlgorithm":"alpha"},"php_unit_strict":true,"php_unit_test_class_requires_covers":true,"phpdoc_add_missing_param_annotation":true,"phpdoc_align":true,"phpdoc_indent":true,"phpdoc_inline_tag":true,"phpdoc_no_access":true,"phpdoc_no_package":true,"phpdoc_no_useless_inheritdoc":true,"phpdoc_order":true,"phpdoc_scalar":true,"phpdoc_separation":true,"phpdoc_single_line_var_spacing":true,"phpdoc_summary":true,"phpdoc_to_comment":true,"phpdoc_trim":true,"phpdoc_types":true,"phpdoc_var_without_name":true,"psr4":true,"self_accessor":true,"semicolon_after_instruction":true,"short_scalar_cast":true,"simplified_null_return":true,"single_blank_line_at_eof":true,"single_blank_line_before_namespace":true,"single_class_element_per_statement":true,"single_import_per_statement":true,"single_line_after_imports":true,"single_line_comment_style":{"comment_types":["hash"]},"single_quote":true,"space_after_semicolon":true,"standardize_not_equals":true,"strict_comparison":true,"strict_param":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"ternary_operator_spaces":true,"trailing_comma_in_multiline_array":true,"trim_array_spaces":true,"unary_operator_spaces":true,"visibility_required":true,"whitespace_after_comma_in_array":true},"hashes":{"tests\/Analysis\/AnalysisTest.php":2269863672,"tests\/Components\/ExportUserDataTest.php":2923185317,"tests\/Components\/UpdateProfilePhotoFormTest.php":490626868,"tests\/Components\/UpdateTimezoneFormTest.php":1498554513,"tests\/TestCase.php":78583716,"tests\/Actions\/CreateNewUserTest.php":2118307707,"tests\/database\/migrations\/2014_10_12_000000_create_users_table.php":1723824529,"tests\/Pest.php":1169021441,"tests\/MediaUser.php":3700109144,"tests\/Helpers.php":1374867389,"resources\/lang\/en\/menu.php":1447561255,"resources\/lang\/en\/pages.php":3678040609,"resources\/lang\/en\/forms.php":851048379,"resources\/lang\/en\/metatags.php":1348954319,"resources\/lang\/en\/auth.php":1987199608,"resources\/lang\/en\/actions.php":528775330,"src\/Components\/UpdateProfileInformationForm.php":1726477055,"src\/Components\/Concerns\/InteractsWithUser.php":604797978,"src\/Components\/Concerns\/ValidatesPassword.php":997171193,"src\/Components\/ExportUserData.php":659094774,"src\/Components\/RegisterForm.php":1011346723,"src\/Components\/UpdateProfilePhotoForm.php":3129785372,"src\/Components\/DeleteUserForm.php":4127726762,"src\/Components\/LogoutOtherBrowserSessionsForm.php":1945407058,"src\/Components\/UpdateTimezoneForm.php":3626051886,"src\/Components\/UpdatePasswordForm.php":3386160155,"src\/Components\/TwoFactorAuthenticationForm.php":3974019434,"src\/Rules\/OneTimePassword.php":1527130763,"src\/Models\/Concerns\/HasPhoto.php":3120665243,"src\/Models\/Concerns\/HasLocalizedTimestamps.php":3255316602,"src\/Models\/User.php":2344707040,"src\/FortifyServiceProvider.php":3020670563,"src\/Models.php":1170854951,"src\/Actions\/UpdateUserPassword.php":3027603934,"src\/Actions\/CreateNewUser.php":1334182225,"src\/Actions\/GenerateTwoFactorAuthenticationSecretKey.php":1464696352,"src\/Actions\/EnableTwoFactorAuthentication.php":167336416,"src\/Actions\/UpdateUserProfileInformation.php":1227061479,"src\/Actions\/DeleteUser.php":2694141662,"src\/Actions\/PasswordValidationRules.php":1174304774,"src\/Actions\/ResetUserPassword.php":1701156092,"src\/Responses\/TwoFactorLoginResponse.php":3770476152,"src\/Responses\/FailedTwoFactorLoginResponse.php":36363793,"config\/fortify.php":543398167}}
7 changes: 7 additions & 0 deletions resources/lang/en/forms.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,11 @@
'requirements_notice' => 'Password must be 12–128 characters, and include a number, a symbol, a lower and an upper case letter.',
],

'password_rules' => [
'needs_lowercase' => 'One lowercase character',
'needs_uppercase' => 'One uppercase character',
'needs_numeric' => 'One number',
'needs_special_character' => 'One special character',
'is_too_short' => '12 characters minumum',
],
];
1 change: 0 additions & 1 deletion resources/views/auth/login.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ class="flex flex-col p-8 mx-4 border rounded-lg border-theme-secondary-200 md:mx
<div class="mb-4">
<div class="flex flex-1">
<x-ark-input
type="email"
name="email"
label="Username or Email"
autocomplete="email"
Expand Down
118 changes: 118 additions & 0 deletions resources/views/auth/register-form.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<form
method="POST"
action="{{ $formUrl }}"
class="flex flex-col p-8 mx-4 border rounded-lg border-theme-secondary-200 md:mx-0 lg:p-8 xl:mx-8"
>
@csrf

@if($invitation)
<input type="hidden" name="name" value="{{ $invitation->name }}" />
@else
<div class="mb-4">
<div class="flex flex-1">
<x-ark-input
model="state.name"
name="name"
label="Name"
autocomplete="name"
class="w-full"
:autofocus="true"
:required="true"
:errors="$errors"
/>
</div>
</div>
@endif

<div class="mb-4">
<div class="flex flex-1">
<x-ark-input
model="state.username"
type="text"
name="username"
label="Username"
autocomplete="username"
class="w-full"
:required="true"
:errors="$errors"
/>
</div>
</div>

@if($invitation)
<input type="hidden" name="email" value="{{ $invitation->email }}" />
@else
<div class="mb-4">
<div class="flex flex-1">
<x-ark-input
model="state.email"
type="email"
name="email"
label="Email"
autocomplete="email"
class="w-full"
:required="true"
:errors="$errors"
/>
</div>
</div>
@endif

<x:ark-fortify::password-rules class="mb-4" :password-rules="$passwordRules">
<x-ark-input
model="state.password"
type="password"
name="password"
label="Password"
autocomplete="new-password"
class="w-full"
:required="true"
:errors="$errors"
/>
</x:ark-fortify::password-rules>

<div class="mb-4">
<div class="flex flex-1">
<x-ark-input
model="state.password_confirmation"
type="password"
name="password_confirmation"
label="Confirm Password"
autocomplete="new-password"
class="w-full"
:required="true"
:errors="$errors"
/>
</div>
</div>

<div class="mb-4">
<x-ark-checkbox
model="state.terms"
name="terms"
:errors="$errors"
>
@slot('label')
Creating an account means you're okay with our
<a href="{{ route('terms-of-service') }}" class="link">Terms of Service</a> and
<a href="{{ route('privacy-policy') }}" class="link">Privacy Policy</a>.
@endslot
</x-ark-checkbox>

@error('terms')
<p class="input-help--error">{{ $message }}</p>
@enderror
</div>

<div class="mt-4 text-right">
<button type="submit" class="w-full button-primary md:w-auto">
Create Account
</button>
</div>

<div class="text-center">
<div class="pt-4 mt-8 border-t border-theme-secondary-200">
Already a member? <a href="/login" class="link">Sign in</a>
</div>
</div>
</form>
121 changes: 1 addition & 120 deletions resources/views/auth/register.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,126 +18,7 @@
<div class="mx-4 mt-2 text-theme-secondary-700 md:mx-8 xl:mx-16">Sign up to MarketSquare and connect with a growing community of like-minded blockchain enthusiasts and developers.</div>

<div class="mt-5 lg:mt-8">
<form
method="POST"
action="{{ $formUrl }}"
class="flex flex-col p-8 mx-4 border rounded-lg border-theme-secondary-200 md:mx-0 lg:p-8 xl:mx-8"
>
@csrf

@if($invitation)
<input type="hidden" name="name" value="{{ $invitation->name }}" />
@else
<div class="mb-4">
<div class="flex flex-1">
<x-ark-input
name="name"
label="Name"
autocomplete="name"
class="w-full"
:autofocus="true"
:value="old('name')"
:required="true"
:errors="$errors"
/>
</div>
</div>
@endif

<div class="mb-4">
<div class="flex flex-1">
<x-ark-input
type="text"
name="username"
label="Username"
autocomplete="username"
class="w-full"
:required="true"
:errors="$errors"
/>
</div>
</div>

@if($invitation)
<input type="hidden" name="email" value="{{ $invitation->email }}" />
@else
<div class="mb-4">
<div class="flex flex-1">
<x-ark-input
type="email"
name="email"
label="Email"
autocomplete="email"
class="w-full"
:value="old('email')"
:required="true"
:errors="$errors"
/>
</div>
</div>
@endif

<div class="mb-4">
<div class="flex flex-1">
<x-ark-input
type="password"
name="password"
label="Password"
autocomplete="new-password"
class="w-full"
:required="true"
:errors="$errors"
/>
</div>

@if (! request()->session()->get('errors'))
<div class="text-sm text-theme-secondary-600">@lang('fortify::forms.update_password.requirements_notice')</div>
@endif
</div>

<div class="mb-4">
<div class="flex flex-1">
<x-ark-input
type="password"
name="password_confirmation"
label="Confirm Password"
autocomplete="new-password"
class="w-full"
:required="true"
:errors="$errors"
/>
</div>
</div>

<div class="mb-4">
<x-ark-checkbox
name="terms"
:errors="$errors"
>
@slot('label')
Creating an account means you're okay with our
<a href="{{ route('terms-of-service') }}" class="link">Terms of Service</a> and
<a href="{{ route('privacy-policy') }}" class="link">Privacy Policy</a>.
@endslot
</x-ark-checkbox>

@error('terms')
<p class="input-help--error">{{ $message }}</p>
@enderror
</div>

<div class="mt-4 text-right">
<button type="submit" class="w-full button-primary md:w-auto">
Create Account
</button>
</div>

<div class="text-center">
<div class="pt-4 mt-8 border-t border-theme-secondary-200">
Already a member? <a href="/login" class="link">Sign in</a>
</div>
</div>
</form>
<livewire:auth.register-form />
</div>
</div>
</div>
Expand Down
19 changes: 19 additions & 0 deletions resources/views/components/password-rules.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
@props(['passwordRules'])

<div {{ $attributes }}>
<div class="flex flex-1">
{{ $slot }}
</div>

<div class="flex flex-wrap -mx-4 text-sm">
@foreach($passwordRules as $ruleName => $ruleIsValid)
<div class="flex items-center w-1/2 px-4 my-1 @if($ruleIsValid) text-theme-secondary-600 @else text-theme-secondary-500 @endif">
<span class="block w-2 h-2 mr-2 rounded-full @if($ruleIsValid) bg-theme-primary-500 @else bg-theme-secondary-400 @endif"></span>

<span>
@lang('fortify::forms.password_rules.' . Str::snake($ruleName))
</span>
</div>
@endforeach
</div>
</div>
6 changes: 5 additions & 1 deletion resources/views/profile/update-password-form.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
<form class="mt-8" wire:submit.prevent="updatePassword">
<div class="space-y-4">
<x-ark-input type="password" name="currentPassword" model="state.current_password" :label="trans('fortify::forms.current_password')" :errors="$errors" />
<x-ark-input type="password" name="password" model="state.password" :label="trans('fortify::forms.new_password')" :errors="$errors" />

<x:ark-fortify::password-rules class="w-full" :password-rules="$passwordRules">
<x-ark-input type="password" name="password" model="state.password" class="w-full" :label="trans('fortify::forms.new_password')" :errors="$errors" />
</x:ark-fortify::password-rules>

<x-ark-input type="password" name="passwordConfirmation" model="state.password_confirmation" :label="trans('fortify::forms.confirm_password')" :errors="$errors" />
</div>
<div class="flex justify-end mt-8">
Expand Down
2 changes: 1 addition & 1 deletion src/Actions/CreateNewUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public function create(array $input)
'name' => ['required', 'string', 'max:255'],
'username' => ['required', 'string', 'max:255', 'unique:users'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'password' => ['required', 'string', $this->passwordRules(), 'confirmed'],
'password' => $this->passwordRules(),
'terms' => ['required', 'accepted'],
])->validate();

Expand Down
2 changes: 1 addition & 1 deletion src/Components/Concerns/InteractsWithUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

trait InteractsWithUser
{
public function getUserProperty(): ?\Illuminate\Contracts\Auth\Authenticatable
public function getUserProperty(): ?Authenticatable
{
return Auth::user();
}
Expand Down
32 changes: 32 additions & 0 deletions src/Components/Concerns/ValidatesPassword.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace ARKEcosystem\Fortify\Components\Concerns;

use Laravel\Fortify\Rules\Password;

trait ValidatesPassword
{
public array $passwordRules = [
'needsLowercase' => false,
'needsUppercase' => false,
'needsNumeric' => false,
'needsSpecialCharacter' => false,
'isTooShort' => false,
];

public function updatedStatePassword($password)
{
$this->errorMessages = [];

$passwordValidator = (new Password())
->length(12)
->requireUppercase()
->requireNumeric()
->requireSpecialCharacter();

collect($this->passwordRules)
->each(function ($val, $ruleName) use ($passwordValidator, $password) {
$this->passwordRules[$ruleName] = ! $passwordValidator->{$ruleName}($password);
});
}
}
Loading

0 comments on commit 9cf0748

Please sign in to comment.