195 lines
6.6 KiB
PHP
195 lines
6.6 KiB
PHP
<?php
|
||
|
||
namespace App\Livewire\Ui\Security;
|
||
|
||
use Illuminate\Support\Facades\Auth;
|
||
use Illuminate\Support\Facades\Hash;
|
||
use Illuminate\Support\Facades\Password;
|
||
use Illuminate\Validation\Rule;
|
||
use Livewire\Component;
|
||
|
||
class AccountSecurityForm extends Component
|
||
{
|
||
// “Company Policy” – hier nur Platzhalter; speicherst du später global
|
||
public bool $require2fa = false;
|
||
public bool $allowTotp = true;
|
||
public bool $allowMail = true;
|
||
|
||
public string $name = '';
|
||
public string $username = '';
|
||
public string $maskedEmail = ''; // nur Anzeige links
|
||
public string $emailInput = ''; // editierbar rechts
|
||
|
||
// aktueller Benutzer
|
||
public bool $userHas2fa = false;
|
||
public bool $totpActive = false;
|
||
public bool $email2faActive = false;
|
||
|
||
// Profil
|
||
public string $email = '';
|
||
|
||
// Passwort
|
||
public string $current_password = '';
|
||
public string $new_password = '';
|
||
public string $new_password_confirmation = '';
|
||
|
||
// E-Mail-2FA
|
||
public string $email_current = '';
|
||
public string $email_new = '';
|
||
|
||
protected $listeners = [
|
||
'totp-enabled' => 'onTotpEnabled',
|
||
'totp-disabled' => 'onTotpDisabled',
|
||
'email2fa-enabled' => 'onEmail2faEnabled',
|
||
'email2fa-disabled' => 'onEmail2faDisabled',
|
||
];
|
||
|
||
public function mount(): void
|
||
{
|
||
$u = Auth::user();
|
||
|
||
$this->name = (string)($u->name ?? '');
|
||
$this->username = (string)($u->username ?? '');
|
||
$this->email = (string)($u->email ?? '');
|
||
$this->maskedEmail = $this->maskEmail($u->email ?? '');
|
||
$this->emailInput = (string)($u->email ?? '');
|
||
|
||
|
||
$this->totpActive = (bool) optional($u->twoFactorMethod('totp'))->enabled;
|
||
$this->email2faActive = (bool) optional($u->twoFactorMethod('email'))->enabled;
|
||
$this->userHas2fa = $u->twoFactorEnabled();
|
||
}
|
||
|
||
|
||
protected function rules(): array
|
||
{
|
||
$userId = Auth::id();
|
||
|
||
return [
|
||
'require2fa' => ['boolean'],
|
||
'allowTotp' => ['boolean'],
|
||
'allowMail' => ['boolean'],
|
||
|
||
'username' => ['required','string','min:3','max:80'],
|
||
'email' => [
|
||
'required','email', Rule::unique('users','email')->ignore($userId)
|
||
],
|
||
|
||
'current_password' => ['nullable','string'],
|
||
'new_password' => ['nullable', Password::min(10)->mixedCase()->numbers()],
|
||
'new_password_confirmation' => ['same:new_password'],
|
||
|
||
'email_current' => ['required','email','in:'.(auth()->user()->email ?? '')],
|
||
'email_new' => ['required','email','different:email_current','max:255','unique:users,email'],
|
||
];
|
||
}
|
||
|
||
/* ===== Aktionen ===== */
|
||
|
||
public function save2faPolicy(): void
|
||
{
|
||
$this->validate([
|
||
'require2fa' => ['boolean'],
|
||
'allowTotp' => ['boolean'],
|
||
'allowMail' => ['boolean'],
|
||
]);
|
||
|
||
// TODO: In einer Settings-Tabelle persistieren
|
||
$this->dispatch('toast', body: '2FA-Richtlinie gespeichert.');
|
||
}
|
||
|
||
// public function toggleUser2fa(): void
|
||
// {
|
||
// // “Globaler” Toggle – wenn nichts aktiv, öffnet der Nutzer die Modals.
|
||
// // Hier nur eine UX-Rückmeldung:
|
||
// if (! $this->userHas2fa) {
|
||
// $this->dispatch('toast', body: 'Wähle und richte zuerst eine Methode ein (TOTP oder E-Mail).');
|
||
// return;
|
||
// }
|
||
//
|
||
// // Wenn mindestens 1 Methode aktiv ist → komplett aus
|
||
// $u = Auth::user();
|
||
// $u->twoFactorMethods()->update(['enabled' => false, 'confirmed_at' => null, 'secret' => null]);
|
||
// $this->totpActive = $this->email2faActive = $this->userHas2fa = false;
|
||
//
|
||
// $this->dispatch('toast', body: '2FA deaktiviert.');
|
||
// }
|
||
|
||
|
||
protected function maskEmail(string $email): string {
|
||
if (!str_contains($email, '@')) return $email;
|
||
[$l, $d] = explode('@', $email, 2);
|
||
$l = strlen($l) <= 2 ? substr($l, 0, 1).'…' : substr($l,0,1).str_repeat('•', max(1, strlen($l)-3)).substr($l,-2);
|
||
$d = preg_replace('/(^.).*(\..{1,4}$)/', '$1…$2', $d);
|
||
return "{$l}@{$d}";
|
||
}
|
||
|
||
public function saveProfile(): void
|
||
{
|
||
$this->validate([
|
||
'username' => ['required','string','min:3','max:80'],
|
||
'email' => ['required','email', Rule::unique('users','email')->ignore(Auth::id())],
|
||
]);
|
||
|
||
$u = Auth::user();
|
||
$u->name = $this->username;
|
||
$u->email = $this->email;
|
||
$u->save();
|
||
|
||
$this->dispatch('toast', body: 'Profil gespeichert.');
|
||
}
|
||
|
||
public function changePassword(): void
|
||
{
|
||
if ($this->new_password === '') {
|
||
$this->dispatch('toast', body: 'Kein neues Passwort eingegeben.');
|
||
return;
|
||
}
|
||
|
||
$this->validate([
|
||
'current_password' => ['required','string'],
|
||
'new_password' => ['required', Password::min(10)->mixedCase()->numbers()],
|
||
'new_password_confirmation' => ['required','same:new_password'],
|
||
]);
|
||
|
||
$u = Auth::user();
|
||
if (! Hash::check($this->current_password, $u->password)) {
|
||
$this->addError('current_password','Aktuelles Passwort ist falsch.');
|
||
return;
|
||
}
|
||
|
||
$u->password = Hash::make($this->new_password);
|
||
$u->save();
|
||
|
||
$this->reset(['current_password','new_password','new_password_confirmation']);
|
||
$this->dispatch('toast', body: 'Passwort aktualisiert.');
|
||
}
|
||
|
||
|
||
public function changeEmail(): void
|
||
{
|
||
$this->validate(['email_current','email_new']);
|
||
|
||
$user = auth()->user();
|
||
$old = $user->email;
|
||
|
||
// 1) neue E-Mail in „pending“ Tabelle/Spalte ablegen (z. B. users.email_pending + token)
|
||
// 2) Verifizierungs-Mail an $this->email_new senden (mit Token)
|
||
// 3) Anzeigen/Toast
|
||
$this->dispatch('toast', body: 'Bestätigungslink an die neue E-Mail gesendet.');
|
||
|
||
// Felder leeren
|
||
$this->reset(['email_current', 'email_new', 'email_new_confirmation']);
|
||
}
|
||
|
||
public function onTotpEnabled() { $this->totpActive = true; $this->userHas2fa = true; }
|
||
public function onTotpDisabled() { $this->totpActive = false; $this->userHas2fa = $this->email2faActive; }
|
||
public function onEmail2faEnabled() { $this->email2faActive = true; $this->userHas2fa = true; }
|
||
public function onEmail2faDisabled(){ $this->email2faActive = false; $this->userHas2fa = $this->totpActive; }
|
||
|
||
public function render()
|
||
{
|
||
return view('livewire.ui.security.account-security-form');
|
||
}
|
||
}
|