86 lines
2.1 KiB
PHP
86 lines
2.1 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Security;
|
|
|
|
use App\Models\IpAttempt;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class IpBanCommandService
|
|
{
|
|
public function banNow(?int $id, ?string $ip, int $hours): ?IpAttempt
|
|
{
|
|
$row = $this->findRow($id, $ip);
|
|
if (! $row) {
|
|
return null;
|
|
}
|
|
|
|
$blockedUntil = $this->addHours($hours);
|
|
$attempts = max((int) $row->attempts, 10);
|
|
|
|
return DB::transaction(function () use ($row, $blockedUntil, $attempts) {
|
|
$row->blocked_until = $blockedUntil;
|
|
$row->attempts = $attempts;
|
|
$row->save();
|
|
|
|
return $row->refresh();
|
|
});
|
|
}
|
|
|
|
public function unbanOne(?int $id, ?string $ip): ?IpAttempt
|
|
{
|
|
$row = $this->findRow($id, $ip);
|
|
if (! $row) {
|
|
return null;
|
|
}
|
|
|
|
return DB::transaction(function () use ($row) {
|
|
$row->blocked_until = null;
|
|
$row->attempts = 0;
|
|
$row->save();
|
|
|
|
return $row->refresh();
|
|
});
|
|
}
|
|
|
|
public function unbanAll(): int
|
|
{
|
|
return (int) IpAttempt::query()
|
|
->where('blocked_until', '>', $this->utcNow())
|
|
->update([
|
|
'blocked_until' => null,
|
|
'attempts' => 0,
|
|
]);
|
|
}
|
|
|
|
private function findRow(?int $id, ?string $ip): ?IpAttempt
|
|
{
|
|
if ($id && $id > 0) {
|
|
return IpAttempt::query()->find($id);
|
|
}
|
|
if ($ip !== null && $ip !== '') {
|
|
return IpAttempt::query()->where('ip_address', $ip)->first();
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private function utcNow(): string
|
|
{
|
|
if (function_exists('utc_now')) {
|
|
return (string) utc_now();
|
|
}
|
|
|
|
return now('UTC')->toDateTimeString();
|
|
}
|
|
|
|
private function addHours(int $hours): string
|
|
{
|
|
$hours = max(1, $hours);
|
|
if (function_exists('utc_now')) {
|
|
return (string) date('Y-m-d H:i:s', strtotime("+{$hours} hours", strtotime((string) utc_now())));
|
|
}
|
|
|
|
return now('UTC')->addHours($hours)->toDateTimeString();
|
|
}
|
|
}
|