changemaker.lite/api/dist/utils/path-validator.js

66 lines
2.4 KiB
JavaScript

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateFilePath = validateFilePath;
const path_1 = __importDefault(require("path"));
const promises_1 = __importDefault(require("fs/promises"));
/**
* Validates that a file path is safe and within the allowed base directory
* Prevents path traversal attacks via:
* - Null byte injection
* - Directory traversal sequences (../)
* - Symlink attacks
*
* @param basePath - The allowed base directory (must be absolute)
* @param relativePath - The relative path to validate
* @returns The validated absolute path
* @throws Error if path validation fails
*/
async function validateFilePath(basePath, relativePath) {
// Check for null bytes
if (relativePath.includes('\0')) {
throw new Error('Invalid file path: contains null byte');
}
// Resolve to absolute path
const fullPath = path_1.default.resolve(basePath, relativePath);
// Verify it's still within base directory
const resolvedBase = path_1.default.resolve(basePath);
if (!fullPath.startsWith(resolvedBase)) {
throw new Error('Invalid file path: directory traversal detected');
}
// Check for symlinks (resolve real path)
try {
const realPath = await promises_1.default.realpath(fullPath);
if (!realPath.startsWith(resolvedBase)) {
throw new Error('Invalid file path: symlink traversal detected');
}
}
catch (err) {
if (err.code === 'ENOENT') {
// File doesn't exist yet, verify parent directory
const parent = path_1.default.dirname(fullPath);
try {
const realParent = await promises_1.default.realpath(parent);
if (!realParent.startsWith(resolvedBase)) {
throw new Error('Invalid file path: parent traversal detected');
}
}
catch (parentErr) {
if (parentErr.code === 'ENOENT') {
// Parent also doesn't exist, just verify the path is within base
// This is already checked above
}
else {
throw parentErr;
}
}
}
else {
throw err;
}
}
return fullPath;
}
//# sourceMappingURL=path-validator.js.map