* - ?token= * * Optional query parameters: * minutes int Lookback window in minutes (default 10, max 1440) * node_id int Filter to a specific node */ require_once __DIR__ . '/../includes/auth.php'; require_once __DIR__ . '/../includes/functions.php'; header('Content-Type: application/json'); // ── Auth ────────────────────────────────────────────────────────────────────── // Accept a valid session from a logged-in browser $session_ok = false; if (auth_enabled()) { if (session_status() === PHP_SESSION_NONE) { session_start(); } $session_ok = !empty($_SESSION['authenticated']); } // Accept a Bearer token or ?token= for programmatic access $token_ok = false; if (TRIGGER_TOKEN !== '') { $provided = ''; $auth_header = $_SERVER['HTTP_AUTHORIZATION'] ?? ''; if (str_starts_with($auth_header, 'Bearer ')) { $provided = substr($auth_header, 7); } if ($provided === '' && isset($_REQUEST['token'])) { $provided = $_REQUEST['token']; } $token_ok = $provided !== '' && hash_equals(TRIGGER_TOKEN, $provided); } if (!$session_ok && !$token_ok) { http_response_code(401); echo json_encode(['error' => 'Unauthorized']); exit; } // ── Parameters ──────────────────────────────────────────────────────────────── $minutes = min(1440, max(1, (int)($_GET['minutes'] ?? 10))); $node_id = isset($_GET['node_id']) ? (int)$_GET['node_id'] : null; // ── Query ───────────────────────────────────────────────────────────────────── $rows = connections_since($minutes, $node_id); $since = date('Y-m-d\TH:i:s\Z', time() - $minutes * 60); echo json_encode([ 'since' => $since, 'minutes' => $minutes, 'count' => count($rows), 'connections' => array_map(fn($r) => [ 'id' => (int)$r['id'], 'occurred_at' => $r['occurred_at'], 'node_id' => (int)$r['node_id'], 'node_name' => $r['node_name'], 'src_ip' => $r['src_ip'], 'src_port' => (int)$r['src_port'], 'dst_port' => (int)$r['dst_port'], 'banner_hex' => $r['banner_hex'], 'banner_len' => (int)$r['banner_len'], ], $rows), ], JSON_PRETTY_PRINT);