feat: 2fa reset notifs
Signed-off-by: miguel456 <me@nogueira.codes>
This commit is contained in:
parent
3122c23eb4
commit
f3996bb68c
@ -30,11 +30,13 @@ use App\Http\Requests\ChangePasswordRequest;
|
||||
use App\Http\Requests\DeleteUserRequest;
|
||||
use App\Http\Requests\FlushSessionsRequest;
|
||||
use App\Http\Requests\Remove2FASecretRequest;
|
||||
use App\Http\Requests\Reset2FASecretRequest;
|
||||
use App\Http\Requests\SearchPlayerRequest;
|
||||
use App\Http\Requests\UpdateUserRequest;
|
||||
use App\Notifications\ChangedPassword;
|
||||
use App\Notifications\EmailChanged;
|
||||
use App\Notifications\PasswordAdminResetNotification;
|
||||
use App\Notifications\TwoFactorResetNotification;
|
||||
use App\Services\AccountSuspensionService;
|
||||
use App\Traits\DisablesFeatures;
|
||||
use App\Traits\HandlesAccountDeletion;
|
||||
@ -446,6 +448,39 @@ class UserController extends Controller
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove the given user's two factor secret key
|
||||
*
|
||||
* @param Reset2FASecretRequest $request
|
||||
* @param User $user
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function reset2FASecret(Reset2FASecretRequest $request, User $user) {
|
||||
|
||||
if ($user->has2FA()) {
|
||||
Log::warning('SECURITY: Disabling two factor authentication (admin initiated)', [
|
||||
'initiator' => $request->user()->email,
|
||||
'target' => $user->email,
|
||||
'ip' => $request->ip(),
|
||||
]);
|
||||
|
||||
$user->twofa_secret = null;
|
||||
$user->password = null;
|
||||
$user->save();
|
||||
|
||||
$user->notify(new TwoFactorResetNotification());
|
||||
|
||||
return redirect()
|
||||
->back()
|
||||
->with('success', __('Two factor removed & user notified.'));
|
||||
}
|
||||
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', 'This user does not have two-factor authentication enabled.');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Demote the given user's privileges
|
||||
*
|
||||
|
@ -44,7 +44,6 @@ class Remove2FASecretRequest extends FormRequest
|
||||
{
|
||||
return [
|
||||
'currentPassword' => 'required|current_password',
|
||||
'consent' => 'required|accepted',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
20
app/Http/Requests/Reset2FASecretRequest.php
Normal file
20
app/Http/Requests/Reset2FASecretRequest.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class Reset2FASecretRequest extends FormRequest
|
||||
{
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'currentPassword' => 'required|current_password',
|
||||
];
|
||||
}
|
||||
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
35
app/Notifications/TwoFactorResetNotification.php
Normal file
35
app/Notifications/TwoFactorResetNotification.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
class TwoFactorResetNotification extends Notification implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public function via($notifiable): array
|
||||
{
|
||||
return ['mail'];
|
||||
}
|
||||
|
||||
public function toMail($notifiable): MailMessage
|
||||
{
|
||||
return (new MailMessage)
|
||||
->from(config('notification.sender.address'), config('notification.sender.name'))
|
||||
->subject(config('app.name').' - your second factor has been reset')
|
||||
->markdown('mail.two-factor-reset', ['name' => $notifiable->name]);
|
||||
}
|
||||
|
||||
public function toArray($notifiable): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
@ -59,9 +59,6 @@
|
||||
|
||||
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
|
||||
|
||||
<script id="help-ukraine-win" async="true" src="https://helpukrainewinwidget.org/cdn/widget.js" data-type="four" data-position="bottom-left"></script>
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<!--Main Navigation-->
|
||||
@ -113,7 +110,7 @@
|
||||
<div class="container text-center white-text">
|
||||
<div class="white-text text-center wow fadeInUp">
|
||||
<h2>{{config('app.name')}}</h2>
|
||||
<h5>{{ __('Welcome to the Games Club Recruitment Portal!') }}</h5>
|
||||
<h5>{{ __('Welcome to the :appName Recruitment Portal!', ['appName' => config('app.name')]) }}</h5>
|
||||
<br>
|
||||
<p>{{ __('We process applications for our Discord server\'s management team here. If you have any questions, don\'t hesistate to contact our support team! Take a look at the open jobs below.') }}</p>
|
||||
<p>{!! __('If you\'d like to learn more about our community, make sure to visit our <a href=":mainWebsiteUrlConfigValue" target="_blank">main website</a>!', ['mainWebsiteUrlConfigValue' => config('app.sitehomepage')]) !!}</p>
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
<label for="otp">{{ __('Two-factor authentication code') }}</label>
|
||||
<input type="text" id="otp" name="otp" class="form-control">
|
||||
<p class="text-muted text-sm"><i class="fas fa-info-circle"></i> $slot</p>
|
||||
<p class="text-muted text-sm"><i class="fas fa-info-circle"></i> {{ $slot }}</p>
|
||||
|
||||
</div>
|
||||
@endif
|
||||
|
@ -15,9 +15,37 @@
|
||||
|
||||
@section('content')
|
||||
|
||||
<x-modal id="resetAccountPasswordModal" modal-label="resetAccountPassword" modal-title="{{ __('Confirm your password') }}" include-close-button="true">
|
||||
@if($user->has2FA())
|
||||
|
||||
<p>{{ __('Please confirm that you want to invalidate this account\'s password. Since this is a sensitive operation, you\'ll need to confirm your own password and provide a 2FA code, if enabled.') }}</p>
|
||||
<x-modal id="resetTwoFactorModal" modal-label="resetTwoFactor" modal-title="{{ __('Verify your identity') }}" include-close-button="true">
|
||||
|
||||
<p>{{ __('Resetting an account\'s two-factor authentication secret will automatically notify the account holder. Additionally, the user\'s password will also be forcefully reset during this process. Please confirm this action by verifying your identity below.') }}</p>
|
||||
|
||||
<form id="resetAccountTwofaForm" method="POST" action="{{ route('reset-twofa', ['user' => $user]) }}">
|
||||
@csrf
|
||||
@method('PATCH')
|
||||
|
||||
<x-confirm-password>
|
||||
{{ __('Please re-enter your password.') }}
|
||||
</x-confirm-password>
|
||||
|
||||
<x-confirm-second-factor>
|
||||
{{ __('Please enter your two-factor authentication code.') }}
|
||||
</x-confirm-second-factor>
|
||||
|
||||
</form>
|
||||
|
||||
<x-slot:modalFooter>
|
||||
<button onclick="$('#resetAccountTwofaForm').submit()" type="button" class="btn btn-warning"><i class="fas fa-check"></i> {{ __('Re-authenticate and verify') }}</button>
|
||||
</x-slot:modalFooter>
|
||||
|
||||
</x-modal>
|
||||
|
||||
@endif
|
||||
|
||||
<x-modal id="resetAccountPasswordModal" modal-label="resetAccountPassword" modal-title="{{ __('Verify your identity') }}" include-close-button="true">
|
||||
|
||||
<p>{{ __('Forcing a password reset will automatically notify the account holder and send them a password reset link. Please confirm this action by verifying your identity below.') }}</p>
|
||||
|
||||
<form id="resetAccountPasswordForm" method="POST" action="{{ route('force-reset-user', ['user' => $user]) }}">
|
||||
@csrf
|
||||
@ -34,7 +62,7 @@
|
||||
</form>
|
||||
|
||||
<x-slot name="modalFooter">
|
||||
<button onclick="$('#resetAccountPasswordForm').submit()" type="button" class="btn btn-warning"><i class="fas fa-check"></i> {{ __('Re-authenticate and confirm') }}</button>
|
||||
<button onclick="$('#resetAccountPasswordForm').submit()" type="button" class="btn btn-warning"><i class="fas fa-check"></i> {{ __('Re-authenticate and verify') }}</button>
|
||||
</x-slot>
|
||||
|
||||
</x-modal>
|
||||
@ -388,7 +416,9 @@
|
||||
</form>
|
||||
@endif
|
||||
<button onclick="$('#resetAccountPasswordModal').modal('show')" class="btn-danger btn mr-3" type="button"><i class="fas fa-key"></i> {{ __('Force password reset') }}</button>
|
||||
<button class="btn-danger btn mr-3" type="button"><i class="fas fa-unlock"></i> {{ __('Reset MFA') }}</button>
|
||||
@if($user->has2FA())
|
||||
<button onclick="$('#resetTwoFactorModal').modal('show')" class="btn-danger btn mr-3" type="button"><i class="fas fa-unlock"></i> {{ __('Reset MFA') }}</button>
|
||||
@endif
|
||||
<button onclick="$('#deleteAccount').modal('show')" type="button" class="btn btn-danger"><i class="fas fa-trash"></i> {{ __('Delete account') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
12
resources/views/mail/two-factor-reset.blade.php
Normal file
12
resources/views/mail/two-factor-reset.blade.php
Normal file
@ -0,0 +1,12 @@
|
||||
@component('mail::message')
|
||||
# Hi {{ $name }},
|
||||
|
||||
Important security notification regarding your account at {{ config('app.name') }}:
|
||||
|
||||
Your account was previously secured with two-factor authentication. This is no longer the case. An administrator has disabled two-factor authentication for your account. Admins only reset two-factor authentication after an identity verification is complete.
|
||||
|
||||
As a result of this action and as an additional security measure, your password has also been voided, which means you'll need to [reset it]({{ route('password.email') }}) if you want to keep using the app.
|
||||
|
||||
Thank you,<br>
|
||||
The team at {{ config('app.name') }}
|
||||
@endcomponent
|
@ -302,6 +302,9 @@ Route::group(['prefix' => LaravelLocalization::setLocale(), 'middleware' => ['lo
|
||||
Route::patch('accounts/force-reset/{user}', [UserController::class, 'forcePasswordReset'])
|
||||
->name('force-reset-user');
|
||||
|
||||
Route::patch('accounts/reset-twofa/{user}', [UserController::class, 'reset2FASecret'])
|
||||
->name('reset-twofa');
|
||||
|
||||
Route::patch('accounts/update/{user}', [UserController::class, 'update'])
|
||||
->name('updateUser');
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user