Delete includes directory

This commit is contained in:
SubleXBle
2025-08-16 20:39:40 +02:00
committed by GitHub
parent d447a95ede
commit c18791e18a
16 changed files with 0 additions and 1198 deletions

View File

@@ -1,66 +0,0 @@
<?php
// includes/actions/action_ban-ip.php
header('Content-Type: application/json; charset=utf-8');
require_once __DIR__ . '/../block-ip.php';
// Check if IP(s) were provided
if (!isset($_POST['ip'])) {
http_response_code(400);
echo json_encode([
'success' => false,
'message' => 'Missing IP address(es)',
'type' => 'error'
]);
exit;
}
// Normalize input
$ips = $_POST['ip'];
if (!is_array($ips)) {
$ips = [$ips]; // Single IP fallback
}
$jail = $_POST['jail'] ?? 'unknown';
$source = $_POST['source'] ?? 'action_ban-ip';
$results = [];
foreach ($ips as $ip) {
$ip = trim($ip);
$result = blockIp($ip, $jail, $source);
// Ensure each result has a type
$type = $result['type'] ?? ($result['success'] ? 'success' : 'error');
$results[] = [
'ip' => $ip,
'success' => $result['success'],
'message' => $result['message'],
'type' => $type
];
}
// HTTP-Status abhängig vom Ergebnis
$hasError = array_filter($results, fn($r) => $r['type'] === 'error');
http_response_code(count($hasError) > 0 ? 207 : 200);
// Dominantesten Typ ermitteln (error > info > success)
$priority = ['error' => 3, 'info' => 2, 'success' => 1];
$finalType = 'success';
foreach ($results as $r) {
if (isset($r['type']) && $priority[$r['type']] > $priority[$finalType]) {
$finalType = $r['type'];
}
}
// Nachrichten zusammenbauen
$messages = array_map(fn($r) => "[{$r['ip']}] {$r['message']}", $results);
$combinedMessage = implode(" | ", $messages);
// Finales JSON
echo json_encode([
'results' => $results,
'message' => $combinedMessage,
'type' => $finalType
], JSON_PRETTY_PRINT);

View File

@@ -1,118 +0,0 @@
<?php
// includes/actions/action_report-ip.php
header('Content-Type: application/json; charset=utf-8');
$config = parse_ini_file('/opt/Fail2Ban-Report/fail2ban-report.config');
$ips = $_POST['ip'] ?? null;
if (!$config['report'] || !$config['report_types'] || !$ips) {
echo json_encode([
'success' => false,
'message' => 'Reporting not enabled or invalid IP(s).',
'type' => 'info',
]);
exit;
}
if (!is_array($ips)) {
$ips = [$ips]; // Convert single IP to array
}
$services = array_map('trim', explode(',', $config['report_types']));
$results = [];
$allMessages = [];
$overallSuccess = true;
foreach ($ips as $ip) {
$ip = trim($ip);
$reportResults = [];
$messages = [];
$ipSuccess = true;
foreach ($services as $service) {
$script = __DIR__ . "/reports/$service.php";
// Check API keys for services that require them
if ($service === 'abuseipdb' && empty($config['abuseipdb_key'])) {
$ipSuccess = false;
$reportResults[$service] = [
'success' => false,
'message' => 'AbuseIPDB API key not set.',
'type' => 'error'
];
$messages[] = "[$service] API key missing";
continue;
}
if ($service === 'ipinfo' && empty($config['ipinfo_key'])) {
$ipSuccess = false;
$reportResults[$service] = [
'success' => false,
'message' => 'IPInfo API key not set.',
'type' => 'error'
];
$messages[] = "[$service] API key missing";
continue;
}
if (file_exists($script)) {
$_POST['ip'] = $ip;
ob_start();
include $script;
$response = ob_get_clean();
// Pause 500ms to avoid hitting API rate limits
usleep(500000);
$decoded = json_decode($response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
$ipSuccess = false;
$reportResults[$service] = [
'success' => false,
'message' => "Invalid JSON from $service: " . json_last_error_msg(),
'raw_response' => $response
];
$messages[] = "[$service] JSON error";
} else {
if (empty($decoded['success'])) {
$ipSuccess = false;
}
$reportResults[$service] = $decoded;
$messages[] = "[$service] " . ($decoded['message'] ?? 'Reported.');
}
} else {
$ipSuccess = false;
$reportResults[$service] = [
'success' => false,
'message' => "$service report script not available",
];
$messages[] = "[$service] not available";
}
}
if (!$ipSuccess) {
$overallSuccess = false;
}
$ipMessage = implode(' | ', $messages);
$allMessages[] = "$ip$ipMessage";
$results[] = [
'ip' => $ip,
'success' => $ipSuccess,
'message' => $ipMessage,
'data' => $reportResults,
];
}
// Final overall message type forced to 'info' for better UI
$finalType = 'info';
$finalMessage = implode(' || ', $allMessages);
echo json_encode([
'success' => $overallSuccess,
'message' => $finalMessage,
'type' => $finalType,
'results' => $results
], JSON_PRETTY_PRINT);

View File

@@ -1,26 +0,0 @@
<?php
// includes/actions/action_unban-ip.php
header('Content-Type: application/json; charset=utf-8');
require_once __DIR__ . '/../unblock-ip.php';
// Validate input
if (!isset($_POST['ip']) || !isset($_POST['jail'])) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'Missing IP address or jail']);
exit;
}
$ip = trim($_POST['ip']);
$jail = trim($_POST['jail']);
// Call the unblock function with jail context
$result = unblockIp($ip, $jail);
if ($result['success']) {
echo json_encode(['success' => true, 'message' => $result['message']]);
} else {
http_response_code(500);
echo json_encode(['success' => false, 'message' => $result['message']]);
}

View File

@@ -1,66 +0,0 @@
<?php
// abuseipdb.php
$config = parse_ini_file('/opt/Fail2Ban-Report/fail2ban-report.config');
$apiKey = trim($config['abuseipdb_key'] ?? '');
if (!$apiKey) {
echo json_encode([
'success' => false,
'message' => 'AbuseIPDB API key not set.',
'type' => 'error'
]);
return;
}
$ipToCheck = $ip ?? null;
if (!$ipToCheck) {
echo json_encode([
'success' => false,
'message' => 'No IP specified for AbuseIPDB check.',
'type' => 'error'
]);
return;
}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.abuseipdb.com/api/v2/check?ipAddress=$ipToCheck",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Key: $apiKey",
"Accept: application/json"
],
]);
$response = curl_exec($curl);
curl_close($curl);
if ($response) {
$json = json_decode($response, true);
$count = $json['data']['totalReports'] ?? null;
if ($count === null) {
echo json_encode([
'success' => false,
'message' => 'AbuseIPDB: Unexpected API response.',
'type' => 'error'
]);
return;
}
$msg = "AbuseIPDB: $ipToCheck was reported $count time(s).";
echo json_encode([
'success' => true,
'message' => $msg,
'type' => ($count >= 10) ? 'error' : (($count > 0) ? 'info' : 'success')
]);
} else {
echo json_encode([
'success' => false,
'message' => 'AbuseIPDB request failed.',
'type' => 'error'
]);
}

View File

@@ -1,77 +0,0 @@
<?php
// ipinfo.php
$config = parse_ini_file('/opt/Fail2Ban-Report/fail2ban-report.config');
$apiKey = trim($config['ipinfo_key'] ?? '');
if (!$apiKey) {
echo json_encode([
'success' => false,
'message' => 'IPInfo API key not set.',
'type' => 'error'
]);
return;
}
$ipToCheck = $ip ?? null;
if (!$ipToCheck) {
echo json_encode([
'success' => false,
'message' => 'No IP specified for IPInfo check.',
'type' => 'error'
]);
return;
}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://ipinfo.io/{$ipToCheck}/json?token={$apiKey}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Accept: application/json"
],
]);
$response = curl_exec($curl);
$curlError = curl_error($curl);
curl_close($curl);
if ($response) {
$json = json_decode($response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
echo json_encode([
'success' => false,
'message' => 'IPInfo: Invalid JSON response.',
'type' => 'error'
]);
return;
}
// Example fields from IPInfo
$ip = $json['ip'] ?? 'unknown';
$hostname = $json['hostname'] ?? 'N/A';
$city = $json['city'] ?? 'N/A';
$region = $json['region'] ?? 'N/A';
$country = $json['country'] ?? 'N/A';
$org = $json['org'] ?? 'N/A';
$loc = $json['loc'] ?? 'N/A';
$postal = $json['postal'] ?? 'N/A';
$msg = "IPInfo: $ip - Hostname: $hostname, Location: $city, $region, $country, Org: $org";
echo json_encode([
'success' => true,
'message' => $msg,
'data' => $json,
'type' => 'info'
]);
} else {
$errorMsg = $curlError ?: 'IPInfo request failed.';
echo json_encode([
'success' => false,
'message' => $errorMsg,
'type' => 'error'
]);
}

View File

@@ -1,171 +0,0 @@
<?php
// includes/block-ip.php
/**
* Blocks one or multiple IP addresses by adding them to their jail-specific blocklist JSON files.
*
* @param string|array $ips IP address or array of IP addresses to block.
* @param string $jail Fail2Ban jail/context name (optional).
* @param string $source Who triggered the block (e.g. 'manual', 'report', etc.)
* @return array Result array or array of results with 'success', 'message' and 'type'.
*/
require_once __DIR__ . "/paths.php";
function blockIp($ips, $jail = 'unknown', $source = 'manual') {
$results = [];
if (!is_array($ips)) {
$ips = [$ips];
}
foreach ($ips as $ip) {
$ip = trim($ip);
// Validate IP address format
if (!filter_var($ip, FILTER_VALIDATE_IP)) {
$results[] = [
'ip' => $ip,
'success' => false,
'message' => "Invalid IP address: $ip",
'type' => 'error'
];
continue;
}
// Sanitize jail name
$safeJail = strtolower(preg_replace('/[^a-z0-9_-]/', '', $jail));
if ($safeJail === '') {
$safeJail = 'unknown';
}
$jsonFile = $GLOBALS["PATHS"]["blocklists"] . $safeJail . ".blocklist.json";
$lockFile = "/tmp/{$safeJail}.blocklist.lock";
// Open lock file
$lockHandle = fopen($lockFile, 'c');
if (!$lockHandle) {
$results[] = [
'ip' => $ip,
'success' => false,
'message' => "[LOCK] Unable to open lock file for {$safeJail}.",
'type' => 'error'
];
continue;
}
if (!flock($lockHandle, LOCK_EX)) {
fclose($lockHandle);
$results[] = [
'ip' => $ip,
'success' => false,
'message' => "[LOCK] Could not acquire lock for {$safeJail}.",
'type' => 'error'
];
continue;
}
// Load existing JSON
$data = [];
if (file_exists($jsonFile)) {
$existing = file_get_contents($jsonFile);
$data = json_decode($existing, true);
if (!is_array($data)) {
$data = []; // fallback if file is corrupted
}
}
// Check if IP already exists
$found = false;
foreach ($data as &$item) {
if ($item['ip'] === $ip) {
$found = true;
if (!isset($item['active']) || $item['active'] === false) {
$item['active'] = true;
$item['lastModified'] = date('c');
if (file_put_contents($jsonFile, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)) === false) {
flock($lockHandle, LOCK_UN);
fclose($lockHandle);
$results[] = [
'ip' => $ip,
'success' => false,
'message' => "[WRITE] Failed to write to {$safeJail}.blocklist.json.",
'type' => 'error'
];
continue 2;
}
flock($lockHandle, LOCK_UN);
fclose($lockHandle);
$results[] = [
'ip' => $ip,
'success' => true,
'message' => "IP $ip was reactivated in {$safeJail}.blocklist.json.",
'type' => 'success'
];
continue 2;
} else {
flock($lockHandle, LOCK_UN);
fclose($lockHandle);
$results[] = [
'ip' => $ip,
'success' => true,
'message' => "IP $ip is already active in {$safeJail}.blocklist.json.",
'type' => 'info'
];
continue 2;
}
}
}
unset($item);
// Add new entry if not found
if (!$found) {
$entry = [
'ip' => $ip,
'jail' => $safeJail,
'source' => $source,
'timestamp' => date('c'),
'expires' => null,
'reason' => '',
'active' => true,
'lastModified' => date('c'),
'tags' => [],
'pending' => true
];
$data[] = $entry;
if (file_put_contents($jsonFile, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)) === false) {
flock($lockHandle, LOCK_UN);
fclose($lockHandle);
$results[] = [
'ip' => $ip,
'success' => false,
'message' => "[WRITE] Failed to write to {$safeJail}.blocklist.json.",
'type' => 'error'
];
continue;
}
flock($lockHandle, LOCK_UN);
fclose($lockHandle);
$results[] = [
'ip' => $ip,
'success' => true,
'message' => "IP $ip was successfully added to {$safeJail}.blocklist.json.",
'type' => 'success'
];
}
}
// Flatten result if only one entry
if (count($results) === 1) {
return $results[0];
}
return [
'success' => true,
'message' => count($results) . ' IP(s) processed.',
'details' => $results,
'type' => 'success'
];
}

View File

@@ -1,57 +0,0 @@
<?php
// Set correct path to your blocklist directory
require_once __DIR__ . "/paths.php";
$blocklistDir = $PATHS["blocklists"];
$stats = [];
foreach (glob($blocklistDir . '*.blocklist.json') as $filepath) {
$filename = basename($filepath);
// Extract jail name (remove .blocklist.json)
$jail = preg_replace('/\.blocklist\.json$/', '', $filename);
if (!$jail) continue;
// Read JSON
$json = file_get_contents($filepath);
if (!$json) continue;
$entries = json_decode($json, true);
if (!is_array($entries)) continue;
// Initialize counters
$active = 0;
$pending = 0;
foreach ($entries as $entry) {
// Count pending entries (pending === true)
if (isset($entry['pending']) && $entry['pending'] === true) {
$pending++;
}
// Count active entries with new rule:
// 1) active === true and pending missing or false
// 2) active === false and pending === true
if (
(isset($entry['active']) && $entry['active'] === true &&
(!isset($entry['pending']) || $entry['pending'] === false))
||
(isset($entry['active']) && $entry['active'] === false &&
isset($entry['pending']) && $entry['pending'] === true)
) {
$active++;
}
}
// Store result
$stats[$jail] = [
'active' => $active,
'pending' => $pending
];
}
// Output JSON
header('Content-Type: application/json');
echo json_encode($stats);

View File

@@ -1,114 +0,0 @@
<?php
header('Content-Type: application/json');
require_once __DIR__ . "/paths.php";
$archiveDirectory = $blocklistDir = $PATHS["fail2ban"];
$files = array_filter(scandir($archiveDirectory), function($file) {
return preg_match('/^fail2ban-events-\d{8}\.json$/', $file);
});
if (!$files) {
echo json_encode([
'ban_count' => 0,
'ban_unique_ips' => 0,
'unban_count' => 0,
'unban_unique_ips' => 0,
'total_events' => 0,
'total_unique_ips' => 0,
'aggregated' => [],
'error' => 'No log files found.'
]);
exit;
}
rsort($files); // newest first
// Heute = neueste Datei
$todayFile = $files[0];
// Aggregationsziel: [yesterday => 1, last_7_days => 7, last_30_days => 30]
$aggregationRanges = [
'yesterday' => 1,
'last_7_days' => 7,
'last_30_days' => 30,
];
// Funktion zur Verarbeitung von Einträgen
function processEntries($entries): array {
$banTotal = 0;
$unbanTotal = 0;
$banIPs = [];
$unbanIPs = [];
foreach ($entries as $entry) {
if (!isset($entry['action'], $entry['ip'])) continue;
if ($entry['action'] === 'Ban') {
$banTotal++;
$banIPs[$entry['ip']] = true;
} elseif ($entry['action'] === 'Unban') {
$unbanTotal++;
$unbanIPs[$entry['ip']] = true;
}
}
return [
'ban_count' => $banTotal,
'ban_unique_ips' => count($banIPs),
'unban_count' => $unbanTotal,
'unban_unique_ips' => count($unbanIPs),
'total_events' => $banTotal + $unbanTotal,
'total_unique_ips' => count(array_unique(array_merge(array_keys($banIPs), array_keys($unbanIPs))))
];
}
// Zähle Bans pro Jail in einem Eintrags-Array
function countBansPerJail(array $entries): array {
$bansPerJail = [];
foreach ($entries as $entry) {
if (!isset($entry['action'], $entry['jail'])) continue;
if ($entry['action'] === 'Ban') {
$jail = $entry['jail'];
if (!isset($bansPerJail[$jail])) {
$bansPerJail[$jail] = 0;
}
$bansPerJail[$jail]++;
}
}
return $bansPerJail;
}
// Zuerst: heutige Datei verarbeiten
$todayPath = $archiveDirectory . '/' . $todayFile;
$todayEntries = json_decode(file_get_contents($todayPath), true);
$todayStats = processEntries($todayEntries);
// Zusätzliche Statistik: Bans pro Jail (nur heute)
$banCountPerJail = countBansPerJail($todayEntries);
// Dann aggregierte Werte berechnen
$aggregatedStats = [];
foreach ($aggregationRanges as $label => $count) {
$aggregatedEntries = [];
// n Dateien überspringen wenn nicht genug vorhanden
for ($i = 1; $i <= $count && isset($files[$i]); $i++) {
$filePath = $archiveDirectory . '/' . $files[$i];
$content = json_decode(file_get_contents($filePath), true);
if (is_array($content)) {
$aggregatedEntries = array_merge($aggregatedEntries, $content);
}
}
$aggregatedStats[$label] = processEntries($aggregatedEntries);
}
// Finales JSON-Resultat mit zusätzlichem Feld ban_count_per_jail
echo json_encode(array_merge($todayStats, [
'aggregated' => $aggregatedStats,
'ban_count_per_jail' => $banCountPerJail,
]));

View File

@@ -1,5 +0,0 @@
<footer class="site-footer">
<div class="footer-content">
<span title="Made with sweat, tears and love by SubleXBle">Made with 🥵, 😿 and ❤️ </span>by <a href="https://github.com/SubleXBle" title="SubleXBle on Github" target="_blank" class="yellowtext">SubleXBle</a> &copy; <?php echo date('Y'); ?> All rights reserved
</div>
</footer>

View File

@@ -1,49 +0,0 @@
<?php
// includes/get-blocklist.php
header('Content-Type: application/json');
require_once __DIR__ . "/paths.php";
$archiveDir = $blocklistDir = $PATHS["blocklists"];
if (!$archiveDir) {
http_response_code(500);
die('Archive directory not found.');
}
$archiveDir .= '/';
// Get all files ending with ".blocklist.json"
$blocklistFiles = glob($archiveDir . '*.blocklist.json');
if (!$blocklistFiles) {
http_response_code(404);
echo json_encode([
'success' => false,
'message' => 'No blocklist files found.'
]);
exit;
}
$allEntries = [];
foreach ($blocklistFiles as $file) {
$content = file_get_contents($file);
if ($content === false) {
// Skip file if reading fails, optionally log the error
continue;
}
$data = json_decode($content, true);
if (!is_array($data)) {
// Skip invalid JSON files
continue;
}
// Append all entries from this file
$allEntries = array_merge($allEntries, $data);
}
// Output the aggregated blocklist entries as JSON
echo json_encode([
'success' => true,
'entries' => $allEntries
]);

View File

@@ -1,21 +0,0 @@
<?php
// includes/get-json.php
require_once __DIR__ . '/paths.php';
$filename = basename($_GET['file'] ?? '');
$filepath = $PATHS["fail2ban"] . '/' . $filename;
// secure: it can only read json from archive
if (
!$filename ||
!preg_match('/^fail2ban-events-\d{8}\.json$/', $filename) ||
strpos(realpath($filepath), realpath($PATHS["fail2ban"])) !== 0 ||
!file_exists($filepath)
) {
http_response_code(404);
exit('Not found');
}
// deliver header and json
header('Content-Type: application/json');
readfile($filepath);

View File

@@ -1,98 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Fail2Ban Report</title>
<meta name="viewport" content="width=device-width, initial-scale=0.8">
<link rel="stylesheet" href="assets/css/style.css" />
<link rel="icon" href="assets/css/favicon-32x32.png" type="image/png">
<script>
const availableFiles = <?php echo $filesJson; ?>;
</script>
<script>
const statsFile = 'fail2ban-events-<?php echo date("Ymd"); ?>.json';
</script>
<script src="assets/js/jsonreader.js" defer></script>
<script src="assets/js/notifications.js"></script>
<script src="assets/js/action-collector.js" defer></script>
<script src="assets/js/action.js" defer></script>
<script src="assets/js/blocklist-overlay.js" defer></script>
<script src="assets/js/fail2ban-logstats.js" defer></script>
<script src="assets/js/blocklist-stats.js"></script>
<script src="assets/js/warnings.js"></script>
<script src="assets/js/table-export.js"></script>
<script src="assets/js/ufw-report.js"></script>
</head>
<body>
<!-- ################################## -->
<form method="post" style="margin-bottom: 1em;">
<label for="server">Server: </label>
<select name="server" id="server" onchange="this.form.submit()">
<?php
foreach ($SERVERS as $key => $name) {
$selected = ($key === $activeServer) ? "selected" : "";
echo "<option value='$key' $selected>$name</option>";
}
?>
</select>
</form>
<!-- ################################## -->
<div class="inline-headlines">
<div>
<h1>Fail2Ban-Report</h1>
<h2>Let's catch the bad guys!</h2>
<div><span title="Beta 5.0"><small>Version : 0.5.0</small></span></div>
</div>
<div id="fail2ban-alerts-container">
<div class="headhead"><span title="Shows Jail | Events | Unique IPs">DoS/Scan/BF:</span></div>
<div id="fail2ban-warning-status" class="fail2ban-status">
<span class="status-dot yellow" id="warning-dot" title="No warnings">🟡</span>
<span class="status-label" id="warning-label">none</span>
</div>
<div id="fail2ban-critical-status" class="fail2ban-status">
<span class="status-dot red" id="critical-dot" title="No criticals">🔴</span>
<span class="status-label" id="critical-label">none</span>
</div>
</div>
<div class="fail2ban-alerts-container">
<div class="headhead">Top 3 Bans/Jails:</div>
<div id="fail2ban-top3-jails" class="toplist"></div>
</div>
<div id="fail2ban-stats">
<div class="headhead">Fail2Ban Today:</div>
<div>🚫 Bans: <span id="fail2ban-bans">--</span></div>
<div>🟢 Unbans: <span id="fail2ban-unbans">--</span></div>
<div>📊 Total: <span id="fail2ban-total">--</span></div>
</div>
<div class="history-stats">
<div class="headhead">Fail2Ban History:</div>
<div class="headstat">🕓 Yesterd: <span id="fail2ban-yesterday">--</span></div>
<div class="headstat">📅 7 Days : <span id="fail2ban-last7">--</span></div>
<div class="headstat">📆 30 Days: <span id="fail2ban-last30">--</span></div>
</div>
<div id="blocklist-stats">
<div class="headhead">Fail2Ban-Report Blocklists:</div>
<div id="blocklist-stats-container">
<!-- JS render Jails here -->
</div>
</div>
</div>

View File

@@ -1,47 +0,0 @@
<?php
// Path to the config file
$configPath = '/opt/Fail2Ban-Report/fail2ban-report.config';
require_once __DIR__ . "/paths.php";
// Read config file and parse the [Fail2Ban-Daily-List-Settings] section
$config = [];
if (file_exists($configPath)) {
$config = parse_ini_file($configPath, true);
}
// Default max days to show if not set in config
$maxDays = 7;
if (isset($config['Fail2Ban-Daily-List-Settings']['max_display_days'])) {
$maxDays = (int)$config['Fail2Ban-Daily-List-Settings']['max_display_days'];
}
$jsonDir = $PATHS["fail2ban"];
//$jsonDir = dirname(__DIR__) . '/archive/swsrv/fail2ban/';
// Collect all matching JSON files with their dates extracted from filenames
$matchedFiles = [];
foreach (scandir($jsonDir) as $filename) {
// Match files like fail2ban-events-YYYYMMDD.json
if (preg_match('/^fail2ban-events-(\d{8})\.json$/', $filename, $matches)) {
$matchedFiles[] = [
'filename' => $filename,
'date' => $matches[1], // Extracted date as string YYYYMMDD
];
}
}
// Sort files by date descending (newest first)
usort($matchedFiles, function($a, $b) {
return strcmp($b['date'], $a['date']); // descending order by date string
});
// Take only the latest $maxDays files
$latestFiles = array_slice($matchedFiles, 0, $maxDays);
// Extract only the filenames for JavaScript consumption
$files = array_column($latestFiles, 'filename');
// Encode the list of files as JSON for frontend use
$filesJson = json_encode(array_values($files));

View File

@@ -1,38 +0,0 @@
<?php
session_start();
// Basepath
$ARCHIVE_ROOT = __DIR__ . "/../archive/";
// List of available Servers (has to be edited by hand for now)
$SERVERS = [
"swsrv" => "Webserver",
"tests" => "Testing"
];
// Standardserver
$DEFAULT_SERVER = "swsrv";
// if selected item in serverdropdown → dont forget it
if (isset($_POST['server']) && array_key_exists($_POST['server'], $SERVERS)) {
$_SESSION['active_server'] = $_POST['server'];
}
// set active Server (Session → Default)
$activeServer = $_SESSION['active_server'] ?? $DEFAULT_SERVER;
/**
* Path for active selected Server
*/
function getPaths($server) {
global $ARCHIVE_ROOT;
$base = $ARCHIVE_ROOT . $server . "/";
return [
"fail2ban" => $base . "fail2ban/",
"blocklists" => $base . "blocklists/",
"ufw" => $base . "ufw/",
];
}
// set Global PATHS-Variable
$PATHS = getPaths($activeServer);

View File

@@ -1,140 +0,0 @@
<?php
// includes/unblock-ip.php
/**
* Unblocks one or multiple IP addresses by marking them inactive
* in their jail-specific blocklist JSON files.
*
* @param string|array $ips IP address or array of IP addresses to unblock.
* @param string $jail Fail2Ban jail/context name (optional).
* @return array Result array or array of results with 'success', 'message' and 'type'.
*/
require_once __DIR__ . "/paths.php";
function unblockIp($ips, $jail = 'unknown') {
$results = [];
if (!is_array($ips)) {
$ips = [$ips];
}
foreach ($ips as $ip) {
$ip = trim($ip);
// Validate IP address format
if (!filter_var($ip, FILTER_VALIDATE_IP)) {
$results[] = [
'ip' => $ip,
'success' => false,
'message' => "Invalid IP address: $ip",
'type' => 'error'
];
continue;
}
// Sanitize jail name
$safeJail = strtolower(preg_replace('/[^a-z0-9_-]/', '', $jail));
if ($safeJail === '') {
$safeJail = 'unknown';
}
$jsonFile = $GLOBALS["PATHS"]["blocklists"] . $safeJail . ".blocklist.json";
$lockFile = "/tmp/{$safeJail}.blocklist.lock";
if (!file_exists($jsonFile)) {
$results[] = [
'ip' => $ip,
'success' => false,
'message' => "[NOTFOUND] Blocklist file {$safeJail}.blocklist.json not found.",
'type' => 'error'
];
continue;
}
// Open lock file
$lockHandle = fopen($lockFile, 'c');
if (!$lockHandle) {
$results[] = [
'ip' => $ip,
'success' => false,
'message' => "[LOCK] Unable to open lock file for {$safeJail}.",
'type' => 'error'
];
continue;
}
if (!flock($lockHandle, LOCK_EX)) {
fclose($lockHandle);
$results[] = [
'ip' => $ip,
'success' => false,
'message' => "[LOCK] Could not acquire lock for {$safeJail}.",
'type' => 'error'
];
continue;
}
// Load existing JSON
$data = json_decode(file_get_contents($jsonFile), true);
if (!is_array($data)) {
$data = [];
}
$found = false;
foreach ($data as &$item) {
if ($item['ip'] === $ip && (!isset($item['active']) || $item['active'] === true)) {
$item['active'] = false;
$item['lastModified'] = date('c');
$found = true;
if (file_put_contents($jsonFile, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)) === false) {
flock($lockHandle, LOCK_UN);
fclose($lockHandle);
$results[] = [
'ip' => $ip,
'success' => false,
'message' => "[WRITE] Failed to update {$safeJail}.blocklist.json.",
'type' => 'error'
];
continue 2;
}
flock($lockHandle, LOCK_UN);
fclose($lockHandle);
$results[] = [
'ip' => $ip,
'success' => true,
'message' => "IP $ip was successfully unblocked in {$safeJail}.blocklist.json.",
'type' => 'success'
];
continue 2;
}
}
unset($item);
flock($lockHandle, LOCK_UN);
fclose($lockHandle);
if (!$found) {
$results[] = [
'ip' => $ip,
'success' => false,
'message' => "[NOTFOUND] IP $ip not active in {$safeJail}.blocklist.json.",
'type' => 'error'
];
}
}
// Flatten result if only one entry
if (count($results) === 1) {
return $results[0];
}
return [
'success' => true,
'message' => count($results) . ' IP(s) processed.',
'details' => $results,
'type' => 'success'
];
}

View File

@@ -1,105 +0,0 @@
<?php
header('Content-Type: application/json');
require_once __DIR__ . "/paths.php";
// read Config
$configPath = '/opt/Fail2Ban-Report/fail2ban-report.config';
if (!file_exists($configPath)) {
echo json_encode(['status' => 'disabled', 'reason' => 'No config found']);
exit;
}
$config = parse_ini_file($configPath, true);
// Warnings only active, when in Config enabled = true steht (bool valid Check)
if (empty($config['Warnings']['enabled']) || !filter_var($config['Warnings']['enabled'], FILTER_VALIDATE_BOOLEAN)) {
echo json_encode(['status' => 'disabled', 'reason' => 'Warnings not enabled']);
exit;
}
// Fallback 20:50 for warn and crit - warnings in header
$thresholdRaw = $config['Warnings']['threshold'] ?? '20:50';
[$warnThreshold, $criticalThreshold] = array_map('intval', explode(':', $thresholdRaw));
// find newest log in archive
$archiveDir = $PATHS["fail2ban"];
$files = array_filter(scandir($archiveDir), fn($f) => preg_match('/^fail2ban-events-\d{8}\.json$/', $f));
rsort($files); // neueste zuerst
$todayFile = $files[0] ?? null;
if (!$todayFile || !file_exists($archiveDir . $todayFile)) {
echo json_encode(['status' => 'error', 'reason' => 'No log data found']);
exit;
}
// load JSON Data
$entries = json_decode(file_get_contents($archiveDir . $todayFile), true);
if (!is_array($entries)) {
echo json_encode(['status' => 'error', 'reason' => 'Invalid JSON log']);
exit;
}
// Group Events - Jail and Minute (Minute als 'Y-m-d H:i')
$jailMinuteEvents = [];
foreach ($entries as $entry) {
if (!isset($entry['action'], $entry['ip'], $entry['jail'], $entry['timestamp'])) continue;
if ($entry['action'] !== 'Ban') continue;
$jail = $entry['jail'];
$ip = $entry['ip'];
$minute = date('Y-m-d H:i', strtotime(str_replace(',', '.', $entry['timestamp'])));
$jailMinuteEvents[$jail][$minute][] = $ip;
}
// Analyze: count Events and unique IPs per Jail per Minute, classify as Warn or Crit
$warnings = [];
$criticals = [];
foreach ($jailMinuteEvents as $jail => $minutes) {
foreach ($minutes as $minute => $ips) {
$eventCount = count($ips);
$uniqueIPCount = count(array_unique($ips));
if ($eventCount >= $criticalThreshold) {
// Critical
if (!isset($criticals[$jail])) {
$criticals[$jail] = ['events' => 0, 'unique_ips' => 0];
}
$criticals[$jail]['events'] += $eventCount;
$criticals[$jail]['unique_ips'] += $uniqueIPCount;
} elseif ($eventCount >= $warnThreshold) {
// Warning (only when not crit)
if (!isset($warnings[$jail])) {
$warnings[$jail] = ['events' => 0, 'unique_ips' => 0];
}
$warnings[$jail]['events'] += $eventCount;
$warnings[$jail]['unique_ips'] += $uniqueIPCount;
}
}
}
// forge response
$response = [
'status' => 'ok',
'warning' => [
'total_events' => array_sum(array_column($warnings, 'events')),
'total_unique_ips' => array_sum(array_column($warnings, 'unique_ips')),
'total_jails' => count($warnings),
'jails' => $warnings,
'jail_names' => array_keys($warnings)
],
'critical' => [
'total_events' => array_sum(array_column($criticals, 'events')),
'total_unique_ips' => array_sum(array_column($criticals, 'unique_ips')),
'total_jails' => count($criticals),
'jails' => $criticals,
'jail_names' => array_keys($criticals)
],
'enabled' => true
];
echo json_encode($response);