'grav-recovery', 'cookie_httponly' => true, 'cookie_secure' => !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off', 'cookie_samesite' => 'Lax', ]); $manager = new RecoveryManager(); $context = $manager->getContext() ?? []; $token = $context['token'] ?? null; $authenticated = $token && isset($_SESSION['grav_recovery_authenticated']) && hash_equals($_SESSION['grav_recovery_authenticated'], $token); $errorMessage = null; $notice = null; if ($_SERVER['REQUEST_METHOD'] === 'POST') { $action = $_POST['action'] ?? ''; if ($action === 'authenticate') { $provided = trim($_POST['token'] ?? ''); if ($token && hash_equals($token, $provided)) { $_SESSION['grav_recovery_authenticated'] = $token; header('Location: ' . $_SERVER['REQUEST_URI']); exit; } $errorMessage = 'Invalid recovery token.'; } elseif ($authenticated) { $service = new SafeUpgradeService(); try { if ($action === 'rollback' && !empty($_POST['manifest'])) { $service->rollback(trim($_POST['manifest'])); $manager->clear(); $_SESSION['grav_recovery_authenticated'] = null; $notice = 'Rollback complete. Please reload Grav.'; } if ($action === 'clear-flag') { $manager->clear(); $_SESSION['grav_recovery_authenticated'] = null; $notice = 'Recovery flag cleared.'; } } catch (\Throwable $e) { $errorMessage = $e->getMessage(); } } else { $errorMessage = 'Authentication required.'; } } $quarantineFile = GRAV_ROOT . '/user/data/upgrades/quarantine.json'; $quarantine = []; if (is_file($quarantineFile)) { $decoded = json_decode(file_get_contents($quarantineFile), true); if (is_array($decoded)) { $quarantine = $decoded; } } $manifestDir = GRAV_ROOT . '/user/data/upgrades'; $snapshots = []; if (is_dir($manifestDir)) { $files = glob($manifestDir . '/*.json'); if ($files) { foreach ($files as $file) { $decoded = json_decode(file_get_contents($file), true); if (!is_array($decoded)) { continue; } $id = $decoded['id'] ?? pathinfo($file, PATHINFO_FILENAME); if (!is_string($id) || $id === '' || strncmp($id, 'snapshot-', 9) !== 0) { continue; } $decoded['id'] = $id; $decoded['file'] = basename($file); $decoded['created_at'] = (int)($decoded['created_at'] ?? filemtime($file) ?: 0); $snapshots[] = $decoded; } if ($snapshots) { usort($snapshots, static function (array $a, array $b): int { return ($b['created_at'] ?? 0) <=> ($a['created_at'] ?? 0); }); } } } $latestSnapshot = $snapshots[0] ?? null; header('Content-Type: text/html; charset=utf-8'); ?>
Grav Recovery ModeThis site is running in recovery mode because Grav detected a fatal error.
Locate the recovery token in user/data/recovery.flag and enter it below.
No upgrade snapshots were found.