- Replace python3/PyYAML Authelia ACL parser with pure PHP (no deps available on Unraid) - Cert tab now pulls live from NPM API instead of cert_monitor.sh — auto-discovers all managed certs sorted by urgency - Watchdog page: add missing GB constant and _fmtBytes/_relTime functions that were causing silent render failure - Rsync settings card: pin to far-right 3 columns (grid-column:6/-1), toggle grid narrowed to 2 columns - Add CLAUDE.md project context file on /boot for session persistence across reboots - claude_startup.sh: symlink CLAUDE.md into /root on array start
130 lines
5.2 KiB
PHP
130 lines
5.2 KiB
PHP
<?php
|
|
header('Content-Type: application/json');
|
|
require_once dirname(__DIR__) . '/include/config.php';
|
|
require_once dirname(__DIR__) . '/include/auth.php';
|
|
|
|
$action = ($_SERVER['REQUEST_METHOD'] === 'POST')
|
|
? trim($_POST['action'] ?? '')
|
|
: trim($_GET['action'] ?? '');
|
|
|
|
$cacheFile = STATE_DIR . '/cert_status.json';
|
|
|
|
// ── Live NPM cert list ────────────────────────────────────────────────────────
|
|
if ($action === 'npm') {
|
|
$raw = vv_npm_req('GET', '/api/nginx/certificates');
|
|
if (!is_array($raw) || isset($raw['_err']))
|
|
die(json_encode(['ok' => false, 'error' => $raw['_err'] ?? 'NPM request failed']));
|
|
|
|
$master = vv_read_conf_raw('master.conf');
|
|
preg_match('/^\s*CERT_WARN_DAYS\s*=\s*(\d+)/m', $master, $w);
|
|
preg_match('/^\s*CERT_CRIT_DAYS\s*=\s*(\d+)/m', $master, $c);
|
|
$warn = (int)($w[1] ?? 30);
|
|
$crit = (int)($c[1] ?? 7);
|
|
$now = time();
|
|
|
|
$certs = [];
|
|
foreach ($raw as $cert) {
|
|
$exp = !empty($cert['expires_on']) ? strtotime($cert['expires_on']) : false;
|
|
$days = $exp !== false ? (int)(($exp - $now) / 86400) : null;
|
|
$status = $days === null ? 'UNKN'
|
|
: ($days < 0 ? 'CRIT'
|
|
: ($days <= $crit ? 'CRIT'
|
|
: ($days <= $warn ? 'WARN' : 'OK')));
|
|
$certs[] = [
|
|
'id' => $cert['id'],
|
|
'nice_name' => $cert['nice_name'] ?? implode(', ', $cert['domain_names'] ?? []),
|
|
'domain_names'=> $cert['domain_names'] ?? [],
|
|
'provider' => $cert['provider'] ?? 'unknown',
|
|
'expires' => !empty($cert['expires_on']) ? substr($cert['expires_on'], 0, 10) : '',
|
|
'days' => $days,
|
|
'status' => $status,
|
|
];
|
|
}
|
|
usort($certs, fn($a, $b) => ($a['days'] ?? PHP_INT_MAX) <=> ($b['days'] ?? PHP_INT_MAX));
|
|
|
|
echo json_encode(['ok' => true, 'certs' => $certs, 'warn_days' => $warn, 'crit_days' => $crit]);
|
|
exit;
|
|
}
|
|
|
|
// ── Read configured domains (without running checks) ─────────────────────────
|
|
if ($action === 'domains') {
|
|
$hostId = vv_detect_host();
|
|
$hostIdUp = strtoupper($hostId);
|
|
$confRaw = ($hostId !== 'unknown') ? vv_read_conf_raw($hostId . '.conf') : '';
|
|
$master = vv_read_conf_raw('master.conf');
|
|
|
|
// Extract CERT_WARN_DAYS / CERT_CRIT_DAYS from master
|
|
preg_match('/^\s*CERT_WARN_DAYS\s*=\s*(\d+)/m', $master, $w);
|
|
preg_match('/^\s*CERT_CRIT_DAYS\s*=\s*(\d+)/m', $master, $c);
|
|
|
|
// Extract domains array from host conf
|
|
$domains = [];
|
|
if (preg_match('/' . $hostIdUp . '_CERT_MONITOR_DOMAINS\s*=\s*\(([^)]*)\)/s', $confRaw, $dm)) {
|
|
preg_match_all('/"([^"]+)"/', $dm[1], $dd);
|
|
$domains = $dd[1] ?? [];
|
|
}
|
|
|
|
echo json_encode([
|
|
'ok' => true,
|
|
'host_id' => $hostId,
|
|
'domains' => $domains,
|
|
'warn_days' => (int)($w[1] ?? 30),
|
|
'crit_days' => (int)($c[1] ?? 7),
|
|
]);
|
|
exit;
|
|
}
|
|
|
|
// ── Run cert_monitor.sh now ───────────────────────────────────────────────────
|
|
if ($action === 'run') {
|
|
$script = SCRIPTS_DIR . '/Monitors/cert_monitor.sh';
|
|
if (!file_exists($script)) {
|
|
echo json_encode(['ok' => false, 'error' => 'cert_monitor.sh not found']);
|
|
exit;
|
|
}
|
|
set_time_limit(180);
|
|
exec('bash ' . escapeshellarg($script) . ' 2>&1', $out, $rc);
|
|
// Read freshly written cache
|
|
$data = file_exists($cacheFile)
|
|
? (json_decode(file_get_contents($cacheFile), true) ?: null)
|
|
: null;
|
|
echo json_encode([
|
|
'ok' => true,
|
|
'data' => $data,
|
|
'output' => array_slice(array_filter(array_map('trim', $out)), 0, 30),
|
|
'rc' => $rc,
|
|
]);
|
|
exit;
|
|
}
|
|
|
|
// ── Default: return cached status ─────────────────────────────────────────────
|
|
if (!file_exists($cacheFile)) {
|
|
// No cache yet — return configured domains so UI can show them unchecked
|
|
$hostId = vv_detect_host();
|
|
$hostIdUp = strtoupper($hostId);
|
|
$confRaw = ($hostId !== 'unknown') ? vv_read_conf_raw($hostId . '.conf') : '';
|
|
$master = vv_read_conf_raw('master.conf');
|
|
|
|
preg_match('/^\s*CERT_WARN_DAYS\s*=\s*(\d+)/m', $master, $w);
|
|
preg_match('/^\s*CERT_CRIT_DAYS\s*=\s*(\d+)/m', $master, $c);
|
|
$domains = [];
|
|
if (preg_match('/' . $hostIdUp . '_CERT_MONITOR_DOMAINS\s*=\s*\(([^)]*)\)/s', $confRaw, $dm)) {
|
|
preg_match_all('/"([^"]+)"/', $dm[1], $dd);
|
|
foreach ($dd[1] ?? [] as $d) {
|
|
$domains[] = ['domain' => $d, 'status' => 'UNKN', 'days' => null, 'expires' => ''];
|
|
}
|
|
}
|
|
|
|
echo json_encode([
|
|
'ok' => true,
|
|
'checked_at' => null,
|
|
'host' => $hostId !== 'unknown' ? strtoupper($hostId) : null,
|
|
'warn_days' => (int)($w[1] ?? 30),
|
|
'crit_days' => (int)($c[1] ?? 7),
|
|
'domains' => $domains,
|
|
]);
|
|
exit;
|
|
}
|
|
|
|
$data = json_decode(file_get_contents($cacheFile), true) ?: [];
|
|
echo json_encode(array_merge(['ok' => true], $data));
|