222 lines
No EOL
5.7 KiB
PHP
222 lines
No EOL
5.7 KiB
PHP
<?php
|
|
// Start session for CSRF token management
|
|
session_start();
|
|
|
|
// CSRF Protection Functions
|
|
function generate_csrf_token() {
|
|
if (empty($_SESSION['csrf_token'])) {
|
|
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
|
}
|
|
return $_SESSION['csrf_token'];
|
|
}
|
|
|
|
function verify_csrf_token($token) {
|
|
// Check if token exists in session and matches submitted token
|
|
if (!isset($_SESSION['csrf_token']) ||
|
|
!isset($token) ||
|
|
!hash_equals($_SESSION['csrf_token'], $token)) {
|
|
|
|
// Log potential CSRF attempt
|
|
error_log('Potential CSRF attack detected');
|
|
|
|
// Destroy session and prevent further execution
|
|
session_destroy();
|
|
die('CSRF token validation failed');
|
|
}
|
|
|
|
// Regenerate token after successful validation for additional security
|
|
unset($_SESSION['csrf_token']);
|
|
generate_csrf_token();
|
|
}
|
|
|
|
// Configuration and include path handling
|
|
include('configuration.php');
|
|
include(PATH.'/Parsedown.php');
|
|
|
|
// Mandatory file and directory checks with CSRF protection
|
|
$requiredChecks = [
|
|
PATH.'/monitors.json' => '<h1>Missing monitors.json</h1>',
|
|
PATH.'/monitors' => '<h1>Missing monitors directory</h1>',
|
|
PATH.'/incidents' => '<h1>Missing incidents directory</h1>'
|
|
];
|
|
|
|
foreach ($requiredChecks as $path => $errorMessage) {
|
|
if (!file_exists($path)) {
|
|
die($errorMessage . '<p>See project documentation for more information.</p>');
|
|
}
|
|
}
|
|
|
|
// Check monitors directory writability
|
|
if (!is_writable(PATH.'/monitors')) {
|
|
die('<h1>Monitors directory is not writable</h1>');
|
|
}
|
|
?><!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<title>HHF Website Monitor</title>
|
|
<meta charset="utf-8">
|
|
<meta name="theme-color" content="#212529">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<link href="style.css" rel="stylesheet">
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.8.2/dist/chart.min.js" crossorigin="anonymous"></script>
|
|
<meta name="csrf-token" content="<?php echo generate_csrf_token(); ?>">
|
|
</head>
|
|
<body>
|
|
<main>
|
|
<h1>HHF Website Monitor</h1>
|
|
|
|
<?php
|
|
|
|
$incidents = array();
|
|
foreach(glob(PATH.'/incidents/*.md') as $incident_file) {
|
|
$incident_filename = str_replace(PATH.'/incidents/', '', $incident_file);
|
|
if(substr($incident_filename, 0, 6) == 'alert_') $incidents[$incident_filename] = 'alert';
|
|
else if(substr($incident_filename, 0, 7) == 'notice_') $incidents[$incident_filename] = 'notice';
|
|
else $incidents['post_'.$incident_filename] = 'post';
|
|
}
|
|
|
|
ksort($incidents);
|
|
foreach($incidents as $incident_filename => $class) {
|
|
if(substr($incident_filename, 0, 5) == 'post_') $incident_filename = substr($incident_filename, 5);
|
|
$Parsedown = new Parsedown();
|
|
echo '<div class="incident '.$class.'">';
|
|
echo $Parsedown->text(file_get_contents(PATH.'/incidents/'.$incident_filename));
|
|
echo '</div>';
|
|
}
|
|
|
|
$monitors = json_decode(file_get_contents(PATH.'/monitors.json'));
|
|
|
|
$i = 0;
|
|
|
|
foreach($monitors as $monitor => $url) {
|
|
|
|
$log = json_decode(file_get_contents(PATH.'/monitors/'.$monitor), TRUE);
|
|
$last = $log[array_key_last($log)];
|
|
|
|
if(is_numeric($last['response'])) {
|
|
$last = ' <span class="status">HTTP/1.1 '.$last['response'].'</span>';
|
|
$class = 'good';
|
|
$graph_color = '#51cf66';
|
|
}
|
|
else {
|
|
$last = ' <span class="status">HTTP/1.1 '.$last['response'].'</span>';
|
|
$class = 'bad';
|
|
$graph_color = '#fa5252';
|
|
}
|
|
|
|
echo '<div class="item"><h2><span class="'.$class.'">⬤</span> '.$monitor.$last.'</h2>';
|
|
|
|
if(file_exists(PATH.'/updates/'.$monitor.'.md')) {
|
|
$Parsedown = new Parsedown();
|
|
echo $Parsedown->text(file_get_contents(PATH.'/updates/'.$monitor.'.md'));
|
|
}
|
|
|
|
$labels = array();
|
|
$data = array();
|
|
|
|
$const = 'ctx'.$i;
|
|
$const_chart = $const.'_'.$const;
|
|
|
|
echo '<div class="bloops">';
|
|
|
|
// do we need bloop padding?
|
|
if(count($log) < 60) {
|
|
$diff = 59 - count($log);
|
|
|
|
for ($x = 0; $x <= $diff; $x++) {
|
|
echo '<span class="bloop" title="Not monitored"></span>';
|
|
}
|
|
}
|
|
|
|
foreach($log as $arr) {
|
|
|
|
$labels[] = "'".date("H:i", $arr['timestamp'])."'";
|
|
|
|
$data[] = @$arr['time'];
|
|
|
|
if(@$arr['time'] > 0) {
|
|
echo '<span class="bloop good" data-status="Up" data-time="'.date("H:i", $arr['timestamp']).'" data-response="'.$arr['response'].'" data-ms="'.$arr['time'].'" data-status="Up at '.date("H:i", $arr['timestamp']).'" title="Up at '.date("H:i", $arr['timestamp']).' ('.$arr['time'].' ms)"></span>';
|
|
}
|
|
else {
|
|
echo '<span class="bloop bad"></span>';
|
|
}
|
|
}
|
|
|
|
$min = min($data);
|
|
$max = max($data);
|
|
|
|
$diff = $max - $min;
|
|
|
|
$max += ($diff / 3);
|
|
$min -= ($diff / 3);
|
|
|
|
if($min < 0) $min = 0;
|
|
|
|
echo '</div>';
|
|
|
|
$chart_id = str_replace('.', '-', $monitor);
|
|
|
|
$labels = implode(', ', $labels);
|
|
$data = implode(', ', $data);
|
|
|
|
$out = <<<EOD
|
|
<canvas id="$chart_id" width="300" height="100"></canvas>
|
|
<script>
|
|
const $const = document.getElementById('$chart_id').getContext('2d');
|
|
const $const_chart = new Chart($const, {
|
|
type: 'line',
|
|
data: {
|
|
labels: [$labels],
|
|
datasets: [{
|
|
label: 'response time',
|
|
data: [$data],
|
|
backgroundColor: '$graph_color',
|
|
borderColor: '$graph_color',
|
|
borderWidth: 2,
|
|
tension: .4
|
|
}]
|
|
},
|
|
options: {
|
|
scales: {
|
|
y: {
|
|
beginAtZero: false,
|
|
min: $min,
|
|
max: $max,
|
|
grid: { display: false, drawBorder: false }
|
|
},
|
|
x: {
|
|
grid: { display: false, drawBorder: false }
|
|
}
|
|
},
|
|
plugins: {
|
|
legend: {
|
|
display: false
|
|
},
|
|
tooltip: {
|
|
callbacks: {
|
|
label: function(context) {
|
|
return context.parsed.y + ' ms';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
</script>
|
|
EOD;
|
|
echo $out;
|
|
echo '</div>';
|
|
$i++;
|
|
}
|
|
|
|
?>
|
|
|
|
<footer>
|
|
|
|
<p>Website Monitor is an open source project. <a href="https://git.hhf.technology/hhf/HHFWebsiteMonitor.git">Download it on Forgejo</a>.</p>
|
|
|
|
</footer>
|
|
|
|
</main>
|
|
</body>
|
|
</html>
|