'danger', 'msg' => 'Pedido rejeitado (token CSRF inválido).']; header('Location: ' . $selfUrl, true, 303); exit; } $uid = isset($_SESSION['user']['id']) ? (int) $_SESSION['user']['id'] : null; $action = $_POST['action'] ?? ''; $ip = trim((string) ($_POST['ip'] ?? '')); if ($action === 'unban' && $ip !== '') { platform_ip_unban($pdo, $ip); if (function_exists('platform_audit')) platform_audit($pdo, 'ip.unban', ['target_type' => 'ip', 'target_label' => $ip]); $_SESSION['ipban_flash'] = ['type' => 'success', 'msg' => "Banimento de $ip levantado. O histórico de infracções mantém-se."]; } elseif ($action === 'ban') { if (!filter_var($ip, FILTER_VALIDATE_IP)) { $_SESSION['ipban_flash'] = ['type' => 'warning', 'msg' => 'Endereço IP inválido.']; } elseif (platform_ip_ban_exempt($ip)) { $_SESSION['ipban_flash'] = ['type' => 'warning', 'msg' => 'Endereços internos não podem ser banidos — o contentor fala consigo próprio para o cron e os health checks.']; } else { $dur = $_POST['duration'] ?? '60'; $mins = $dur === 'perm' ? null : max(1, (int) $dur); $reason = trim((string) ($_POST['reason'] ?? '')) ?: 'banido manualmente'; platform_ip_ban($pdo, $ip, $reason, $mins, 'manual', $uid); if (function_exists('platform_audit')) platform_audit($pdo, 'ip.ban', ['target_type' => 'ip', 'target_label' => $ip, 'summary' => $reason, 'changes' => ['minutes' => $mins]]); $_SESSION['ipban_flash'] = ['type' => 'success', 'msg' => "$ip banido."]; } } header('Location: ' . $selfUrl, true, 303); exit; } $flash = $_SESSION['ipban_flash'] ?? null; unset($_SESSION['ipban_flash']); $bans = platform_ip_ban_list($pdo); $offenders = platform_ip_offenders($pdo, 7); $activos = array_values(array_filter($bans, fn($b) => empty($b['expired']))); $layout_header = $platform_layout_header ?? ($repo_root . '/includes/header.php'); $layout_navbar = $platform_layout_navbar ?? ($repo_root . '/includes/navbar.php'); $layout_footer = $platform_layout_footer ?? ($repo_root . '/includes/footer.php'); $pageTitle = 'Bloqueio de IP'; if (is_file($layout_header)) include $layout_header; if (is_file($layout_navbar)) include $layout_navbar; $h = fn($s) => htmlspecialchars((string) $s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); ?>
Endereços recusados à porta por atividade automatizada repetida.
Nenhum endereço banido até agora.
| IP | Motivo | Origem | Até | Infr. | Tentat. | |
|---|---|---|---|---|---|---|
= $h($b['ip']) ?> |
= $h($b['reason']) ?> | >= $h($b['source'] === 'fleet' ? 'frota' : $b['source']) ?> | permanente = $h(substr((string) $b['expires_at'], 0, 16)) ?> expirou | = (int) $b['offences'] ?> | = (int) $b['hits'] ?> |
Tentat. é quantas vezes o endereço voltou depois de banido — um número alto é o sinal mais claro de que não é uma pessoa.
Nenhuma infracção registada no período.
| IP | Infracções | Tipos | Última | |
|---|---|---|---|---|
= $h($o['ip']) ?> |
= (int) $o['n'] ?> | = $h($o['kinds']) ?> | = $h(substr((string) $o['last_seen'], 0, 16)) ?> |