diff --git a/app/Console/Commands/UnbanIp.php b/app/Console/Commands/UnbanIp.php new file mode 100644 index 0000000..76c910f --- /dev/null +++ b/app/Console/Commands/UnbanIp.php @@ -0,0 +1,41 @@ +option('all')) { + $count = BannedIp::query()->count(); + foreach (BannedIp::query()->pluck('ip') as $ip) { + Cache::forget('bruteforce:banned:'.$ip); + } + BannedIp::query()->delete(); + $this->info("{$count} Bann/Bänne entfernt."); + + return self::SUCCESS; + } + + $ip = (string) $this->argument('ip'); + if ($ip === '') { + $this->error('Bitte eine IP angeben oder --all verwenden.'); + + return self::FAILURE; + } + + $guard->unban($ip); + $this->info("Bann für {$ip} entfernt (falls vorhanden)."); + + return self::SUCCESS; + } +} diff --git a/docker/clusev/clusev b/docker/clusev/clusev index 9f2658f..845722c 100644 --- a/docker/clusev/clusev +++ b/docker/clusev/clusev @@ -19,6 +19,7 @@ clusev — Fleet-Control Verwaltung (Host) sudo clusev update Update holen, Image neu bauen, Migrationen anwenden (root) clusev reset-admin Admin-Zugang zuruecksetzen (2FA entfernen, Passwort neu setzen) + clusev unban Gebannte IP entsperren (--all fuer alle) clusev restart Stack neu starten clusev logs [dienst] Logs folgen (Strg-C beendet) clusev ps Dienst-Status (Alias: status) @@ -38,6 +39,7 @@ cmd="${1:-help}"; shift 2>/dev/null || true case "$cmd" in update) exec "${CLUSEV_DIR}/update.sh" "$@" ;; reset-admin) compose exec app php artisan clusev:reset-admin "$@" ;; + unban) compose exec app php artisan clusev:unban "$@" ;; restart) compose up -d "$@" ;; logs) compose logs -f "$@" ;; ps|status) compose ps "$@" ;; diff --git a/tests/Feature/UnbanCommandTest.php b/tests/Feature/UnbanCommandTest.php new file mode 100644 index 0000000..1fc5882 --- /dev/null +++ b/tests/Feature/UnbanCommandTest.php @@ -0,0 +1,32 @@ + '203.0.113.5', 'banned_until' => now()->addHour(), 'attempts' => 10]); + $this->artisan('clusev:unban', ['ip' => '203.0.113.5'])->assertSuccessful(); + $this->assertDatabaseCount('banned_ips', 0); + } + + public function test_unban_all(): void + { + BannedIp::create(['ip' => '203.0.113.5', 'banned_until' => now()->addHour(), 'attempts' => 10]); + BannedIp::create(['ip' => '203.0.113.6', 'banned_until' => now()->addHour(), 'attempts' => 10]); + $this->artisan('clusev:unban', ['--all' => true])->assertSuccessful(); + $this->assertDatabaseCount('banned_ips', 0); + } + + public function test_unban_without_args_fails(): void + { + $this->artisan('clusev:unban')->assertFailed(); + } +}