UNPKG

@stacksjs/router

Version:
38 lines (37 loc) 1.48 kB
export class PathParamError extends Error { reason; constructor(reason, value, context) { const ctx = context ? ` in ${context}` : ""; super(`[router] Refusing to use ${JSON.stringify(value)} as a path parameter${ctx} \u2014 ${reason}`); this.name = "PathParamError"; this.reason = reason; } } const CONTROL_CHARS = /[\u0000-\u001F\u007F]/; export function sanitizePathParam(value, options = {}) { if (typeof value !== "string") throw new PathParamError("not-string", value, options.context); if (value.length === 0) throw new PathParamError("empty", value, options.context); const maxLength = options.maxLength ?? 255; if (value.length > maxLength) throw new PathParamError("too-long", value, options.context); if (value.includes("\x00")) throw new PathParamError("null-byte", value, options.context); if (CONTROL_CHARS.test(value)) throw new PathParamError("control-char", value, options.context); if (value.startsWith("/") || /^[A-Z]:[\\/]/i.test(value)) throw new PathParamError("absolute-path", value, options.context); if (/(^|[\\/])\.\.([\\/]|$)/.test(value)) throw new PathParamError("traversal", value, options.context); if (!options.allowSlashes && /[\\/]/.test(value)) throw new PathParamError("traversal", value, options.context); return value; } export function safePathParam(value, options = {}) { try { return sanitizePathParam(value, options); } catch { return null; } }