diff --git a/Plugin/unraid/api/flag_toggle.php b/Plugin/unraid/api/flag_toggle.php index 795265d..77d2067 100644 --- a/Plugin/unraid/api/flag_toggle.php +++ b/Plugin/unraid/api/flag_toggle.php @@ -34,10 +34,14 @@ // OPERATIONAL SAFEGUARDS // POST only, checked before any parameter is read. // -// The flag name is constrained to the rsync namespace. -// ^[A-Z_]+_RSYNC_ENABLED$ — this endpoint cannot be used to flip an unrelated boolean -// in master.conf. Every other conf edit goes through confform.php or config.php, which -// have their own rules; a general-purpose flag setter would bypass all of them. +// The flag name is constrained to the rsync namespace, with the tier prefix optional. +// ^([A-Z][A-Z_]*_)?RSYNC_ENABLED$ — this endpoint cannot be used to flip an unrelated +// boolean in master.conf. Every other conf edit goes through confform.php or config.php, +// which have their own rules; a general-purpose flag setter would bypass all of them. +// +// The prefix must be optional because RSYNC_ENABLED is itself the global gate, and the +// page renders it alongside the tier flags. Requiring a prefix rejected it as an invalid +// flag name, so the master switch could not be turned on from the UI at all. // // Anything other than the literal "1" is treated as false. // ($_POST['enabled'] ?? '0') === '1' — strict comparison against one value, so a @@ -79,7 +83,11 @@ if ($_SERVER['REQUEST_METHOD'] !== 'POST') { $name = trim($_POST['name'] ?? ''); $enabled = ($_POST['enabled'] ?? '0') === '1'; -if (!$name || !preg_match('/^[A-Z_]+_RSYNC_ENABLED$/', $name)) { +// The tier prefix is optional. RSYNC_ENABLED itself is the global gate the page also renders, +// and requiring a prefix silently rejected it — the toggle reverted to off with no way to turn +// syncing on from the UI at all. Masked until now because every POST to this endpoint was +// being swallowed by the multipart bug. +if (!$name || !preg_match('/^([A-Z][A-Z_]*_)?RSYNC_ENABLED$/', $name)) { echo json_encode(['ok' => false, 'error' => 'Invalid flag name']); exit; }