import { runSsh, shellQuote, resolveFolderRemoteDir, REMOTE_ROOT, } from "../utils/ssh.ts" import {process} from "std-env"; const MAX_FILES_PER_FOLDER = Number(process.env.BACKUPS_MAX_FILES) const isSafeFolder = (value: string) => /^[a-zA-Z0-9._-]+$/.test(value) function isMissingPathError(error: unknown): boolean { const message = String(error || "").toLowerCase() return message.includes("no such file or directory") || message.includes("cannot access") } function toServerError(error: unknown) { console.error("Erreur backups:", error) return createError({ statusCode: 500, statusMessage: "Erreur lors de l'opération" }) } function parseLines(output: string): string[] { return output .split("\n") .map((line) => line.trim()) .filter(Boolean) } function quoteDir(pathValue: string) { return shellQuote(pathValue) } async function listRemoteFiles(remoteDir: string): Promise { const output = await runSsh( `cd ${quoteDir(remoteDir)} && ls -1A | sort -r | head -n ${MAX_FILES_PER_FOLDER}` ) return parseLines(output) } async function listRemoteDirs(remoteRoot: string): Promise { const output = await runSsh( `cd ${quoteDir(remoteRoot)} && for d in */; do [ -d "$d" ] && printf '%s\n' "\${d%/}"; done` ) return parseLines(output) } async function getLatestRemoteFile(remoteDir: string): Promise { const output = await runSsh( `cd ${quoteDir(remoteDir)} && ls -1A | sort -r | head -n 1` ) const files = parseLines(output) return files[0] || null } export default defineEventHandler(async (event) => { const { folder } = getQuery(event) const folderName = typeof folder === "string" ? folder : null // Si un dossier est demandé, on retourne sa liste de fichiers. if (folderName) { if (!isSafeFolder(folderName)) { throw createError({ statusCode: 400, statusMessage: "Paramètre folder invalide" }) } const remoteDir = await resolveFolderRemoteDir(folderName) if (!remoteDir) return [] try { return await listRemoteFiles(remoteDir) } catch (error) { if (isMissingPathError(error)) return [] throw toServerError(error) } } // Sinon, on récupère le dernier backup de chaque dossier distant. let dirs: string[] = [] try { dirs = await listRemoteDirs(REMOTE_ROOT) } catch (error) { throw toServerError(error) } const result: Array<{ folder: string; last: string | null }> = [] for (const dirName of dirs) { const remoteDir = `${REMOTE_ROOT}/${dirName}` try { result.push({ folder: dirName, last: await getLatestRemoteFile(remoteDir) }) } catch (error) { if (isMissingPathError(error)) { result.push({ folder: dirName, last: null }) continue } throw toServerError(error) } } return result })