UNPKG

kequapp

Version:

DEPRECATED: renamed to @kequtech/arbor

57 lines (56 loc) 2.43 kB
import fs from 'node:fs'; import path from 'node:path'; import { Ex } from "../ex.js"; import { createAction } from "../router/modules.js"; import { guessContentType } from "../utils/guess-content-type.js"; import { validateArray, validateExists, validateObject, validatePathname, } from "../utils/validate.js"; import { sendFile } from "./send-file.js"; export function staticDirectory(options) { validateOptions(options); const root = getAbsolute(process.cwd(), options.location); return createAction(async ({ req, res, params }) => { const wild = params.wild ?? ''; const location = await getLocation(root, options.location, wild, options.index); const contentType = guessContentType(location, options.contentTypes); await sendFile(req, res, location, contentType); }); } function validateOptions(options) { validateExists(options, 'Static directory options'); validateObject(options, 'Static directory options'); validateExists(options.location, 'Static directory options.location'); validatePathname(options.location, 'Static directory options.location'); validateArray(options.index, 'Static directory options.index', 'string'); validateObject(options.contentTypes, 'Static directory options.contentTypes', 'string'); } async function getLocation(root, location, wild, index = []) { // Prevent traversal outside the static root const absolute = getAbsolute(root, wild); const relative = path.relative(root, absolute); if (relative.startsWith('..') || relative.includes('../')) { throw Ex.Forbidden('invalid path', { root, absolute }); } try { const stats = await fs.promises.stat(absolute); if (stats.isDirectory() && index.length > 0) { const files = await fs.promises.readdir(absolute); for (const file of index) { if (files.includes(file)) { const indexPath = path.join(location, relative, file); return indexPath; } } } if (stats.isFile()) { const relFromCwd = path.relative(process.cwd(), absolute); return relFromCwd; } } catch { // fall through to NotFound } throw Ex.NotFound(undefined, { absolute, index }); } function getAbsolute(root, location) { return path.resolve(root, location.replace(/^\/+/, '')); }