docs: implementation plan — control-plane brute-force ban (Anmeldeschutz)

9-task TDD plan: BannedIp model, BruteforceGuard (inet_pton CIDR + cache),
ValidIpOrCidr rule, guests-only BlockBannedIp middleware + 403 page, Login/2FA
failure hooks + audit, clusev:unban CLI, Anmeldeschutz settings tab with R5
confirm-modal unban. Spec erratum: middleware is appended (not prepended) so
Auth::guest() resolves for the guests-only check.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
feat/v1-foundation
boban 2026-06-20 17:20:52 +02:00
parent fe8c25c824
commit 9756f9d463
2 changed files with 1395 additions and 4 deletions

File diff suppressed because it is too large Load Diff

View File

@ -101,9 +101,12 @@ New model `App\Models\BannedIp` + migration `banned_ips`:
## 4. `BlockBannedIp` middleware — enforcement (guests only)
New `App\Http\Middleware\BlockBannedIp`, **prepended to the `web` group BEFORE `PanelScheme`** in
[`bootstrap/app.php`](../../../bootstrap/app.php) (prepend array = `[BlockBannedIp::class, PanelScheme::class]`).
trustProxies has already resolved the real IP by then (§0).
New `App\Http\Middleware\BlockBannedIp`, **appended to the `web` group** (last, after
`AuthenticateSession`) in [`bootstrap/app.php`](../../../bootstrap/app.php). It must be **appended, not
prepended**: the guests-only check needs `Auth::guest()`, which requires the session middleware
(`StartSession`) to have already run — a prepended middleware runs before it and would see every
request as a guest (blocking authenticated operators too). `request()->ip()` is still correct because
`trustProxies` is a global middleware that runs before the whole web group (§0).
- If the feature is disabled → pass (one cached `Setting` read; no DB hit).
- **Block guests only:** if `Auth::guest()` **and** `BruteforceGuard::isBanned(request()->ip())`
@ -190,7 +193,7 @@ New: `app/Models/BannedIp.php`, `database/migrations/xxxx_create_banned_ips_tabl
`app/Services/BruteforceGuard.php`, `app/Http/Middleware/BlockBannedIp.php`, `app/Rules/ValidIpOrCidr.php`,
`app/Console/Commands/UnbanIp.php` (`clusev:unban`), `app/Livewire/Settings/LoginProtection.php` +
`resources/views/livewire/settings/login-protection.blade.php`, `resources/views/errors/blocked.blade.php`,
the feature tests. Modify: `bootstrap/app.php` (prepend `BlockBannedIp` before `PanelScheme`),
the feature tests. Modify: `bootstrap/app.php` (append `BlockBannedIp` to the web group),
`app/Livewire/Auth/Login.php` + `app/Livewire/Concerns/CompletesTwoFactorChallenge.php` (record + audit
hooks), `resources/views/livewire/settings/index.blade.php` (new tab + `@else` default), `lang/de/settings.php`,
`lang/en/settings.php`, `lang/de/errors.php`, `lang/en/errors.php`, `docker/clusev/clusev` (add `unban`).