Carry the CSRF token on fetch requests and put mutations behind POST

Unraid already enforces CSRF on every POST via auto_prepend, but its
injector is jQuery-only — the plugin's native fetch() calls carried no
token and were being terminated before the endpoint ran, silently,
because csrf_terminate exits with an empty body that r.json() swallows.
This commit is contained in:
Gmer4Lfe
2026-08-02 10:28:53 -04:00
parent 987313e7dc
commit c34224effa
16 changed files with 198 additions and 67 deletions
+13 -4
View File
@@ -67,15 +67,17 @@
// response is treated as a certificate list — so an unreachable NPM is reported as such
// instead of rendering as zero certificates.
//
// Accepted: the run action is reachable over GET.
// It re-runs a read-only monitor and writes only its own cache, so repeating it is
// harmless. Guarded by the Unraid WebGUI session; see the CSRF note in README-unraid.md.
// The run action is POST only, which is what places it behind Unraid's CSRF guard.
// The platform prepend validates the token on every POST and inspects no GET at all, so
// an action that executes a script must not be reachable by GET. The three read actions
// stay GET-reachable because they change nothing.
//
// REQUEST
// GET cached status, or the configured domains when no cache exists
// GET|POST ?action=npm live certificate list from NPM's API
// GET|POST ?action=domains configured domains and thresholds, no checks run
// GET|POST ?action=run re-run cert_monitor.sh, then return its fresh cache
// POST action=run re-run cert_monitor.sh, then return its fresh cache
// (POST, so Unraid's CSRF guard applies)
//
// RESPONSE
// default {"ok":true,"checked_at","host","warn_days","crit_days","domains":[…]}
@@ -167,6 +169,13 @@ if ($action === 'domains') {
// ── Run cert_monitor.sh now ───────────────────────────────────────────────────
if ($action === 'run') {
// POST only. This executes a script, and Unraid's CSRF prepend validates POSTs while
// ignoring GETs entirely — over GET it would run with no token check at all.
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode(['ok' => false, 'error' => 'POST only']);
exit;
}
$script = SCRIPTS_DIR . '/Monitors/cert_monitor.sh';
if (!file_exists($script)) {
echo json_encode(['ok' => false, 'error' => 'cert_monitor.sh not found']);