import { existsSync, statSync } from "fs"; import path from "path"; import isSafePath from "./is-safe-path"; /** * Maps a URL path onto a file in `dir`, in this order: * - `..` segments (encoded or not) are resolved against `/`, so they * can never climb above `dir`; the 403 check is a second guard * - 404 if there is no such file (so callers can fall through to pages) * - 403 if a symlink points outside `dir` */ export default function resolvePublicFile(dir, url_path) { let decoded; try { decoded = decodeURIComponent(url_path); } catch { return { status: 404 }; } const root = path.resolve(dir); const file_path = path.resolve(root, "." + path.posix.join("/", decoded)); if (file_path !== root && !file_path.startsWith(root + path.sep)) { return { status: 403 }; } if (!existsSync(file_path) || !statSync(file_path).isFile()) { return { status: 404 }; } if (!isSafePath({ filePath: file_path, allowedDir: root })) { return { status: 403 }; } return { status: 200, file_path }; }