@stacksjs/router
Version:
The Stacks framework router.
38 lines (37 loc) • 1.48 kB
JavaScript
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;
}
}