149 lines
5.3 KiB
PHP
Executable File
149 lines
5.3 KiB
PHP
Executable File
<?php
|
|
|
|
namespace App\Controllers\View;
|
|
|
|
use App\Controllers\BaseController;
|
|
use App\Models\IpAttemptModel;
|
|
|
|
class IpBanController extends BaseController
|
|
{
|
|
protected $ipAttemptModel;
|
|
|
|
public function __construct()
|
|
{
|
|
$this->ipAttemptModel = new IpAttemptModel();
|
|
helper(['url', 'form']);
|
|
}
|
|
|
|
public function index()
|
|
{
|
|
$now = utc_now();
|
|
$status = strtolower(trim((string)($this->request->getGet('status') ?? 'all')));
|
|
|
|
$builder = $this->ipAttemptModel->orderBy('updated_at', 'DESC');
|
|
if ($status === 'active') {
|
|
$builder = $builder->where('blocked_until >', $now);
|
|
}
|
|
|
|
$banned = $builder->findAll();
|
|
|
|
return view('administrator/ip_bans', [
|
|
'banned' => $banned,
|
|
'status' => $status,
|
|
'now' => $now,
|
|
]);
|
|
}
|
|
|
|
public function unban()
|
|
{
|
|
$isAjax = $this->request->isAJAX();
|
|
$json = function(array $p, int $code=200){
|
|
$p['csrfTokenName'] = csrf_token();
|
|
$p['csrfHash'] = csrf_hash();
|
|
$p[csrf_token()] = csrf_hash();
|
|
return $this->response->setStatusCode($code)->setJSON($p);
|
|
};
|
|
|
|
$id = (int) $this->request->getPost('id');
|
|
$ip = trim((string) $this->request->getPost('ip'));
|
|
$all = (int) $this->request->getPost('all') === 1;
|
|
|
|
try {
|
|
if ($all) {
|
|
// Clear all active bans
|
|
$now = utc_now();
|
|
$builder = $this->ipAttemptModel->builder();
|
|
$builder->where('blocked_until >', $now)
|
|
->set(['blocked_until' => null, 'attempts' => 0])
|
|
->update();
|
|
|
|
$cnt = $this->ipAttemptModel->db->affectedRows();
|
|
$msg = $cnt . ' IP(s) unbanned.';
|
|
return $isAjax ? $json(['ok'=>true,'message'=>$msg,'count'=>$cnt])
|
|
: redirect()->to(site_url('administrator/ip_bans'))->with('success', $msg);
|
|
}
|
|
|
|
$row = null;
|
|
if ($id > 0) {
|
|
$row = $this->ipAttemptModel->find($id);
|
|
} elseif ($ip !== '') {
|
|
$row = $this->ipAttemptModel->where('ip_address', $ip)->first();
|
|
}
|
|
|
|
if (!$row) {
|
|
$msg = 'IP record not found.';
|
|
return $isAjax ? $json(['ok'=>false,'message'=>$msg],404)
|
|
: redirect()->back()->with('error', $msg);
|
|
}
|
|
|
|
$ok = $this->ipAttemptModel->update($row['id'], [
|
|
'blocked_until' => null,
|
|
'attempts' => 0,
|
|
]);
|
|
|
|
if (!$ok) {
|
|
throw new \RuntimeException('Failed to update record.');
|
|
}
|
|
|
|
$msg = 'IP ' . $row['ip_address'] . ' unbanned.';
|
|
return $isAjax ? $json(['ok'=>true,'message'=>$msg])
|
|
: redirect()->to(site_url('administrator/ip_bans'))->with('success', $msg);
|
|
} catch (\Throwable $e) {
|
|
$msg = 'Unable to unban: ' . $e->getMessage();
|
|
return $isAjax ? $json(['ok'=>false,'message'=>$msg],500)
|
|
: redirect()->back()->with('error', $msg);
|
|
}
|
|
}
|
|
|
|
public function banNow()
|
|
{
|
|
$isAjax = $this->request->isAJAX();
|
|
$json = function(array $p, int $code=200){
|
|
$p['csrfTokenName'] = csrf_token();
|
|
$p['csrfHash'] = csrf_hash();
|
|
$p[csrf_token()] = csrf_hash();
|
|
return $this->response->setStatusCode($code)->setJSON($p);
|
|
};
|
|
|
|
// Accept both POST and GET params
|
|
$id = (int) ($this->request->getPost('id') ?? $this->request->getGet('id') ?? 0);
|
|
$ip = trim((string) ($this->request->getPost('ip') ?? $this->request->getGet('ip') ?? ''));
|
|
$hours = (int) ($this->request->getPost('hours') ?? $this->request->getGet('hours') ?? 24);
|
|
if ($hours <= 0) $hours = 24;
|
|
|
|
try {
|
|
$row = null;
|
|
if ($id > 0) {
|
|
$row = $this->ipAttemptModel->find($id);
|
|
} elseif ($ip !== '') {
|
|
$row = $this->ipAttemptModel->where('ip_address', $ip)->first();
|
|
}
|
|
|
|
if (!$row) {
|
|
$msg = 'IP record not found.';
|
|
return $isAjax ? $json(['ok'=>false,'message'=>$msg],404)
|
|
: redirect()->to(site_url('administrator/ip_bans'))->with('error', $msg);
|
|
}
|
|
|
|
$blockedUntil = date('Y-m-d H:i:s', strtotime("+{$hours} hours"));
|
|
$ok = $this->ipAttemptModel->update($row['id'], [
|
|
'blocked_until' => $blockedUntil,
|
|
// Optionally set attempts to threshold for clarity
|
|
'attempts' => max((int)$row['attempts'], 10),
|
|
]);
|
|
|
|
if (!$ok) {
|
|
throw new \RuntimeException('Failed to update record.');
|
|
}
|
|
|
|
$msg = 'IP ' . $row['ip_address'] . ' banned for ' . $hours . 'h.';
|
|
return $isAjax ? $json(['ok'=>true,'message'=>$msg])
|
|
: redirect()->to(site_url('administrator/ip_bans'))->with('success', $msg);
|
|
} catch (\Throwable $e) {
|
|
$msg = 'Unable to ban: ' . $e->getMessage();
|
|
return $isAjax ? $json(['ok'=>false,'message'=>$msg],500)
|
|
: redirect()->back()->with('error', $msg);
|
|
}
|
|
}
|
|
}
|