120 lines
3.6 KiB
PHP
120 lines
3.6 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire\Settings;
|
|
|
|
use App\Models\AuditEvent;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Validation\Rule;
|
|
use Illuminate\Validation\Rules\Password;
|
|
use Livewire\Attributes\Layout;
|
|
use Livewire\Attributes\On;
|
|
use Livewire\Attributes\Url;
|
|
use Livewire\Component;
|
|
|
|
#[Layout('layouts.app')]
|
|
class Index extends Component
|
|
{
|
|
#[Url]
|
|
public string $tab = 'profile';
|
|
|
|
public bool $openRecoveryModal = false;
|
|
|
|
public string $name = '';
|
|
|
|
public string $email = '';
|
|
|
|
public string $current_password = '';
|
|
|
|
public string $password = '';
|
|
|
|
public string $password_confirmation = '';
|
|
|
|
public function mount(): void
|
|
{
|
|
$this->name = Auth::user()->name;
|
|
$this->email = Auth::user()->email;
|
|
|
|
if (session('open_recovery_modal')) {
|
|
$this->tab = 'security';
|
|
$this->openRecoveryModal = true;
|
|
}
|
|
}
|
|
|
|
public function updateProfile(): void
|
|
{
|
|
$data = $this->validate([
|
|
'name' => ['required', 'string', 'max:255'],
|
|
'email' => ['required', 'email', 'max:255', Rule::unique('users', 'email')->ignore(Auth::id())],
|
|
]);
|
|
|
|
Auth::user()->update($data);
|
|
$this->audit('profile.update', $data['email']);
|
|
$this->dispatch('notify', message: __('settings.profile_saved'));
|
|
}
|
|
|
|
public function updatePassword(): void
|
|
{
|
|
$this->validate([
|
|
'current_password' => ['required', 'current_password'],
|
|
'password' => ['required', 'confirmed', Password::min(10)],
|
|
]);
|
|
|
|
Auth::user()->update(['password' => $this->password, 'must_change_password' => false]);
|
|
$this->reset('current_password', 'password', 'password_confirmation');
|
|
$this->audit('password.change', Auth::user()->email);
|
|
$this->dispatch('notify', message: __('settings.password_changed'));
|
|
}
|
|
|
|
public function confirmDisableTwoFactor(): void
|
|
{
|
|
$this->dispatch('openModal',
|
|
component: 'modals.confirm-action',
|
|
arguments: [
|
|
'heading' => __('settings.disable_2fa_heading'),
|
|
'body' => __('settings.disable_2fa_body'),
|
|
'confirmLabel' => __('common.disable'),
|
|
'danger' => true,
|
|
'icon' => 'shield',
|
|
'auditAction' => 'two_factor.disable',
|
|
'auditTarget' => Auth::user()?->email,
|
|
'event' => 'twoFactorDisabled',
|
|
'notify' => __('settings.disable_2fa_notify'),
|
|
],
|
|
);
|
|
}
|
|
|
|
#[On('twoFactorDisabled')]
|
|
public function disableTwoFactor(): void
|
|
{
|
|
// Reset the whole second factor: clearing 2FA must also drop the backup codes
|
|
// and security keys, so re-enrolling later starts clean (old keys/codes never
|
|
// silently become valid again).
|
|
Auth::user()->forceFill([
|
|
'two_factor_secret' => null,
|
|
'two_factor_confirmed_at' => null,
|
|
'two_factor_recovery_codes' => null,
|
|
])->save();
|
|
|
|
Auth::user()->webauthnCredentials()->delete();
|
|
}
|
|
|
|
private function audit(string $action, string $target): void
|
|
{
|
|
AuditEvent::create([
|
|
'user_id' => Auth::id(),
|
|
'actor' => Auth::user()->name,
|
|
'action' => $action,
|
|
'target' => $target,
|
|
'ip' => request()->ip(),
|
|
]);
|
|
}
|
|
|
|
public function render()
|
|
{
|
|
return view('livewire.settings.index', [
|
|
'twoFactorEnabled' => Auth::user()->hasTwoFactorEnabled(),
|
|
'hasTotp' => Auth::user()->hasTotp(),
|
|
])->title(__('settings.title'));
|
|
}
|
|
}
|