148 lines
4.2 KiB
PHP
Executable File
148 lines
4.2 KiB
PHP
Executable File
<?php
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Http\Requests\ProfileUpdateRequest;
|
|
use App\Support\Security\TotpService;
|
|
use Illuminate\Http\RedirectResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\Crypt;
|
|
use Illuminate\Support\Facades\Redirect;
|
|
use Illuminate\Validation\ValidationException;
|
|
use Illuminate\View\View;
|
|
|
|
class ProfileController extends Controller
|
|
{
|
|
/**
|
|
* Display the user's profile form.
|
|
*/
|
|
public function edit(Request $request): View
|
|
{
|
|
$user = $request->user();
|
|
$pendingSecret = session('two_factor_pending_secret');
|
|
$pendingUri = null;
|
|
|
|
if ($pendingSecret && $user) {
|
|
$pendingUri = app(TotpService::class)->buildOtpAuthUri(
|
|
config('app.name', 'NetGescon'),
|
|
(string) $user->email,
|
|
(string) $pendingSecret
|
|
);
|
|
}
|
|
|
|
return view('profile.edit', [
|
|
'user' => $user,
|
|
'twoFactorPendingSecret' => $pendingSecret,
|
|
'twoFactorPendingUri' => $pendingUri,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Update the user's profile information.
|
|
*/
|
|
public function update(ProfileUpdateRequest $request): RedirectResponse
|
|
{
|
|
$request->user()->fill($request->validated());
|
|
|
|
if ($request->user()->isDirty('email')) {
|
|
$request->user()->email_verified_at = null;
|
|
}
|
|
|
|
$request->user()->save();
|
|
|
|
return Redirect::route('profile.edit')->with('status', 'profile-updated');
|
|
}
|
|
|
|
/**
|
|
* Delete the user's account.
|
|
*/
|
|
public function destroy(Request $request): RedirectResponse
|
|
{
|
|
$request->validateWithBag('userDeletion', [
|
|
'password' => ['required', 'current_password'],
|
|
]);
|
|
|
|
$user = $request->user();
|
|
|
|
Auth::logout();
|
|
|
|
$user->delete();
|
|
|
|
$request->session()->invalidate();
|
|
$request->session()->regenerateToken();
|
|
|
|
return Redirect::to('/');
|
|
}
|
|
|
|
public function twoFactorEnable(Request $request, TotpService $totp): RedirectResponse
|
|
{
|
|
$user = $request->user();
|
|
if (! $user) {
|
|
abort(403);
|
|
}
|
|
|
|
$secret = $totp->generateSecret();
|
|
$request->session()->put('two_factor_pending_secret', $secret);
|
|
|
|
return Redirect::route('profile.edit')->with('status', 'two-factor-pending');
|
|
}
|
|
|
|
public function twoFactorConfirm(Request $request, TotpService $totp): RedirectResponse
|
|
{
|
|
$request->validate([
|
|
'code' => ['required', 'digits:6'],
|
|
]);
|
|
|
|
$user = $request->user();
|
|
$secret = (string) $request->session()->get('two_factor_pending_secret', '');
|
|
|
|
if (! $user || $secret === '') {
|
|
throw ValidationException::withMessages([
|
|
'code' => 'Sessione 2FA scaduta. Riavvia la procedura.',
|
|
]);
|
|
}
|
|
|
|
if (! $totp->verify($secret, (string) $request->input('code'))) {
|
|
throw ValidationException::withMessages([
|
|
'code' => 'Codice 2FA non valido.',
|
|
]);
|
|
}
|
|
|
|
$recoveryCodes = collect(range(1, 8))
|
|
->map(fn() => strtoupper(bin2hex(random_bytes(4))))
|
|
->all();
|
|
|
|
$user->forceFill([
|
|
'two_factor_secret' => Crypt::encryptString($secret),
|
|
'two_factor_recovery_codes' => Crypt::encryptString(json_encode($recoveryCodes)),
|
|
'two_factor_confirmed_at' => now(),
|
|
])->save();
|
|
|
|
$request->session()->forget('two_factor_pending_secret');
|
|
|
|
return Redirect::route('profile.edit')->with('status', 'two-factor-enabled');
|
|
}
|
|
|
|
public function twoFactorDisable(Request $request): RedirectResponse
|
|
{
|
|
$request->validate([
|
|
'password' => ['required', 'current_password'],
|
|
]);
|
|
|
|
$user = $request->user();
|
|
if (! $user) {
|
|
abort(403);
|
|
}
|
|
|
|
$user->forceFill([
|
|
'two_factor_secret' => null,
|
|
'two_factor_recovery_codes' => null,
|
|
'two_factor_confirmed_at' => null,
|
|
])->save();
|
|
|
|
$request->session()->forget('two_factor_pending_secret');
|
|
|
|
return Redirect::route('profile.edit')->with('status', 'two-factor-disabled');
|
|
}
|
|
}
|