auth: Firmenrechte nur aus nachgewiesener Adresse, 2FA auf allen Login-Wegen (Audit Block 1, Deploy A)

Audit vom 11.09. gegen HEAD geprüft, Entwicklungsplan dazu unter
dev/2026-09-11-audit/ENTWICKLUNGSPLAN.md. Dieser Commit ist Deploy A:
die sechs kleinen Punkte aus Block 1 ohne Schemaänderung.

F01: Der Fortify-Endpunkt PUT /user/profile-information tauschte die
E-Mail sofort und setzte die Verifizierung zurück; der Login-Sync vergab
danach Firmenrechte allein nach E-Mail-Treffer. Feature abgeschaltet
(die Kunden-UI hat den pending_email-Prozess), und der Sync verlangt
jetzt ein verifiziertes, aktives Konto – für alle Aufrufer.

F02: Google-Login übergibt Konten mit bestätigtem TOTP in die Challenge,
wie Passwort- und Magic-Link-Login.

F03: showRecoveryCodes ist gesperrt; ein Client-Update konnte die
Recovery-Codes entschlüsseln lassen.

F08: Nutzer-Detailroute unter can:users:manage (persistente Livewire-
Middleware), Gutschriften autorisieren zusätzlich in der Action.

F09: Gate::before greift nur für aktive Super-Admins; deaktivierte
fallen auf die Gates mit is_active-Prüfung zurück.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-09-18 10:08:55 +00:00
parent edb2d49199
commit 1d76f5a733
20 changed files with 2229 additions and 69 deletions

View file

@ -38,6 +38,8 @@ new #[Layout('components.layouts.app'), Title('Benutzer anzeigen')] class extend
public function grantCredits(): void
{
$this->authorize('users:manage');
$this->validate([
'grantCreditsAmount' => ['required', 'integer', 'min:1', 'max:100000'],
'grantCreditsNote' => ['nullable', 'string', 'max:240'],
@ -62,6 +64,8 @@ new #[Layout('components.layouts.app'), Title('Benutzer anzeigen')] class extend
public function grantFreePressReleases(): void
{
$this->authorize('users:manage');
$this->validate([
'grantPmCount' => ['required', 'integer', 'min:1', 'max:100'],
'grantPmNote' => ['nullable', 'string', 'max:240'],

View file

@ -17,6 +17,7 @@ use Laravel\Fortify\Actions\EnableTwoFactorAuthentication;
use Laravel\Fortify\Actions\GenerateNewRecoveryCodes;
use Laravel\Fortify\Features;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Locked;
use Livewire\Attributes\Title;
use Livewire\Volt\Component;
@ -35,7 +36,10 @@ new #[Layout('components.layouts.app'), Title('Konto-Sicherheit')] class extends
/**
* Recovery-Codes werden nur direkt nach Bestätigung bzw. Neu-Erzeugung
* angezeigt (einmalige Sichtbarkeit), nicht bei jedem Seitenaufruf.
* Gesperrt (Audit F03): nur der Server schaltet die Anzeige frei, ein
* Client-Update der Property darf die Codes nicht entschlüsseln.
*/
#[Locked]
public bool $showRecoveryCodes = false;
public function mount(): void