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); } } }