From 8e6306cb412d92b895d2e12246e2d9d8c39ee604 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Fri, 4 Mar 2022 16:13:11 +0100 Subject: [PATCH 1/7] Confirm 2FA in Livewire --- .../Livewire/TwoFactorAuthenticationForm.php | 56 +++++++++++++++++++ .../two-factor-authentication-form.blade.php | 28 +++++++++- 2 files changed, 82 insertions(+), 2 deletions(-) diff --git a/src/Http/Livewire/TwoFactorAuthenticationForm.php b/src/Http/Livewire/TwoFactorAuthenticationForm.php index ba804f84f..5cd03fd7d 100644 --- a/src/Http/Livewire/TwoFactorAuthenticationForm.php +++ b/src/Http/Livewire/TwoFactorAuthenticationForm.php @@ -3,6 +3,7 @@ namespace Laravel\Jetstream\Http\Livewire; use Illuminate\Support\Facades\Auth; +use Laravel\Fortify\Actions\ConfirmTwoFactorAuthentication; use Laravel\Fortify\Actions\DisableTwoFactorAuthentication; use Laravel\Fortify\Actions\EnableTwoFactorAuthentication; use Laravel\Fortify\Actions\GenerateNewRecoveryCodes; @@ -21,6 +22,13 @@ class TwoFactorAuthenticationForm extends Component */ public $showingQrCode = false; + /** + * Indicates if two factor authentication confirmation input and button are being displayed. + * + * @var bool + */ + public $showingConfirmation = false; + /** * Indicates if two factor authentication recovery codes are being displayed. * @@ -28,6 +36,26 @@ class TwoFactorAuthenticationForm extends Component */ public $showingRecoveryCodes = false; + /** + * The OTP code for confirming 2FA. + * + * @var string|null + */ + public $code; + + /** + * Mount the component. + * + * @return void + */ + public function mount() + { + if (Features::optionEnabled(Features::twoFactorAuthentication(), 'confirm') && + is_null(Auth::user()->two_factor_confirmed_at)) { + app(DisableTwoFactorAuthentication::class)(Auth::user()); + } + } + /** * Enable two factor authentication for the user. * @@ -43,6 +71,30 @@ public function enableTwoFactorAuthentication(EnableTwoFactorAuthentication $ena $enable(Auth::user()); $this->showingQrCode = true; + + if (Features::optionEnabled(Features::twoFactorAuthentication(), 'confirm')) { + $this->showingConfirmation = true; + } else { + $this->showingRecoveryCodes = true; + } + } + + /** + * Confirm two factor authentication for the user. + * + * @param \Laravel\Fortify\Actions\ConfirmTwoFactorAuthentication $confirm + * @return void + */ + public function confirmTwoFactorAuthentication(ConfirmTwoFactorAuthentication $confirm) + { + if (Features::optionEnabled(Features::twoFactorAuthentication(), 'confirmPassword')) { + $this->ensurePasswordIsConfirmed(); + } + + $confirm(Auth::user(), $this->code); + + $this->showingQrCode = false; + $this->showingConfirmation = false; $this->showingRecoveryCodes = true; } @@ -90,6 +142,10 @@ public function disableTwoFactorAuthentication(DisableTwoFactorAuthentication $d } $disable(Auth::user()); + + $this->showingQrCode = false; + $this->showingConfirmation = false; + $this->showingRecoveryCodes = false; } /** diff --git a/stubs/livewire/resources/views/profile/two-factor-authentication-form.blade.php b/stubs/livewire/resources/views/profile/two-factor-authentication-form.blade.php index 88d8f3865..0960cbc44 100644 --- a/stubs/livewire/resources/views/profile/two-factor-authentication-form.blade.php +++ b/stubs/livewire/resources/views/profile/two-factor-authentication-form.blade.php @@ -10,7 +10,11 @@

@if ($this->enabled) - {{ __('You have enabled two factor authentication.') }} + @if ($showingConfirmation) + {{ __('You are enabling two factor authentication.') }} + @else + {{ __('You have enabled two factor authentication.') }} + @endif @else {{ __('You have not enabled two factor authentication.') }} @endif @@ -26,13 +30,27 @@ @if ($showingQrCode)

- {{ __('Two factor authentication is now enabled. Scan the following QR code using your phone\'s authenticator application.') }} + @if ($showingConfirmation) + {{ __('Scan the following QR code using your phone\'s authenticator application and confirm it with the generated OTP code.') }} + @else + {{ __('Two factor authentication is now enabled. Scan the following QR code using your phone\'s authenticator application.') }} + @endif

{!! $this->user->twoFactorQrCodeSvg() !!}
+ + @if ($showingConfirmation) +
+ + + +
+ @endif @endif @if ($showingRecoveryCodes) @@ -64,6 +82,12 @@ {{ __('Regenerate Recovery Codes') }} + @elseif ($showingConfirmation) + + + {{ __('Confirm') }} + + @else From 7e83ffaa0b1007654d8c1890c59544e650d33ba7 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Fri, 4 Mar 2022 16:15:39 +0100 Subject: [PATCH 2/7] Bump fortify --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index b9df2d8cd..527398ebf 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ "ext-json": "*", "illuminate/support": "^8.37|^9.0", "jenssegers/agent": "^2.6", - "laravel/fortify": "^1.9" + "laravel/fortify": "^1.11.1" }, "require-dev": { "inertiajs/inertia-laravel": "^0.5.2", From ad938ff1b197e8f79d9d2cb96544852e752251d1 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 15 Mar 2022 10:20:47 -0500 Subject: [PATCH 3/7] formatting --- .../Livewire/TwoFactorAuthenticationForm.php | 4 +-- .../two-factor-authentication-form.blade.php | 29 +++++++++++++------ 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/Http/Livewire/TwoFactorAuthenticationForm.php b/src/Http/Livewire/TwoFactorAuthenticationForm.php index 5cd03fd7d..0f0f27ffd 100644 --- a/src/Http/Livewire/TwoFactorAuthenticationForm.php +++ b/src/Http/Livewire/TwoFactorAuthenticationForm.php @@ -23,7 +23,7 @@ class TwoFactorAuthenticationForm extends Component public $showingQrCode = false; /** - * Indicates if two factor authentication confirmation input and button are being displayed. + * Indicates if the two factor authentication confirmation input and button are being displayed. * * @var bool */ @@ -37,7 +37,7 @@ class TwoFactorAuthenticationForm extends Component public $showingRecoveryCodes = false; /** - * The OTP code for confirming 2FA. + * The OTP code for confirming two factor authentication. * * @var string|null */ diff --git a/stubs/livewire/resources/views/profile/two-factor-authentication-form.blade.php b/stubs/livewire/resources/views/profile/two-factor-authentication-form.blade.php index 0960cbc44..eda90d486 100644 --- a/stubs/livewire/resources/views/profile/two-factor-authentication-form.blade.php +++ b/stubs/livewire/resources/views/profile/two-factor-authentication-form.blade.php @@ -11,7 +11,7 @@

@if ($this->enabled) @if ($showingConfirmation) - {{ __('You are enabling two factor authentication.') }} + {{ __('Finish enabling two factor authentication.') }} @else {{ __('You have enabled two factor authentication.') }} @endif @@ -31,7 +31,7 @@

@if ($showingConfirmation) - {{ __('Scan the following QR code using your phone\'s authenticator application and confirm it with the generated OTP code.') }} + {{ __('To finish enabling two factor authentication, scan the following QR code using your phone\'s authenticator application and provide the generated OTP code.') }} @else {{ __('Two factor authentication is now enabled. Scan the following QR code using your phone\'s authenticator application.') }} @endif @@ -45,9 +45,11 @@ @if ($showingConfirmation)

- +
@endif @@ -84,7 +86,7 @@ @elseif ($showingConfirmation) - + {{ __('Confirm') }} @@ -96,11 +98,20 @@ @endif - - - {{ __('Disable') }} - - + @if ($showingConfirmation) + + + {{ __('Cancel') }} + + + @else + + + {{ __('Disable') }} + + + @endif + @endif
From 232f025635a2ad2839d86412175805bc3c657262 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 15 Mar 2022 11:36:18 -0500 Subject: [PATCH 4/7] inertia support --- .../Inertia/UserProfileController.php | 33 ++++++++ .../Partials/TwoFactorAuthenticationForm.vue | 84 +++++++++++++++++-- .../resources/js/Pages/Profile/Show.vue | 9 +- .../two-factor-authentication-form.blade.php | 2 +- 4 files changed, 117 insertions(+), 11 deletions(-) diff --git a/src/Http/Controllers/Inertia/UserProfileController.php b/src/Http/Controllers/Inertia/UserProfileController.php index 4c1ab69f6..325c0d071 100644 --- a/src/Http/Controllers/Inertia/UserProfileController.php +++ b/src/Http/Controllers/Inertia/UserProfileController.php @@ -5,8 +5,11 @@ use Illuminate\Http\Request; use Illuminate\Routing\Controller; use Illuminate\Support\Carbon; +use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; use Jenssegers\Agent\Agent; +use Laravel\Fortify\Actions\DisableTwoFactorAuthentication; +use Laravel\Fortify\Features; use Laravel\Jetstream\Jetstream; class UserProfileController extends Controller @@ -19,7 +22,37 @@ class UserProfileController extends Controller */ public function show(Request $request) { + $currentTime = time(); + + // Notate totally disabled state in session... + if (Features::optionEnabled(Features::twoFactorAuthentication(), 'confirm') && + is_null(Auth::user()->two_factor_secret) && + is_null(Auth::user()->two_factor_confirmed_at)) { + $request->session()->put('two_factor_empty_at', $currentTime); + } + + // If was previously totally disabled this session but is now confirming, notate time... + if (Features::optionEnabled(Features::twoFactorAuthentication(), 'confirm') && + ! is_null(Auth::user()->two_factor_secret) && + is_null(Auth::user()->two_factor_confirmed_at) && + $request->session()->has('two_factor_empty_at') && + is_null($request->session()->get('two_factor_confirming_at'))) { + $request->session()->put('two_factor_confirming_at', $currentTime); + } + + // If the profile is reloaded and is not confirmed but was previously in confirming state, disable... + if (Features::optionEnabled(Features::twoFactorAuthentication(), 'confirm') && + is_null(Auth::user()->two_factor_confirmed_at) && + // Don't disable if confirmation was first noted during this same request... + $request->session()->get('two_factor_confirming_at', 0) != $currentTime) { + app(DisableTwoFactorAuthentication::class)(Auth::user()); + + $request->session()->put('two_factor_empty_at', $currentTime); + $request->session()->remove('two_factor_confirming_at'); + } + return Jetstream::inertia()->render($request, 'Profile/Show', [ + 'confirmsTwoFactorAuthentication' => Features::optionEnabled(Features::twoFactorAuthentication(), 'confirm'), 'sessions' => $this->sessions($request)->all(), ]); } diff --git a/stubs/inertia/resources/js/Pages/Profile/Partials/TwoFactorAuthenticationForm.vue b/stubs/inertia/resources/js/Pages/Profile/Partials/TwoFactorAuthenticationForm.vue index 8e3625751..057041b59 100644 --- a/stubs/inertia/resources/js/Pages/Profile/Partials/TwoFactorAuthenticationForm.vue +++ b/stubs/inertia/resources/js/Pages/Profile/Partials/TwoFactorAuthenticationForm.vue @@ -9,10 +9,14 @@