import path from 'path';
import os from 'os';
import { getAllowedRoots } from './config.js';
import { ToolError, ERROR_CODES } from './errors.js';
export function validatePath(root: string, relativePath: string): string {
const allowedRoots = getAllowedRoots();
const resolvedRoot = path.resolve(root);
const isWindows = os.platform() === 'win32';
// Check if resolvedRoot is in allowedRoots
const isAllowed = allowedRoots.some(r => {
if (isWindows) return r.toLowerCase() === resolvedRoot.toLowerCase();
return r === resolvedRoot;
});
if (!isAllowed) {
throw new ToolError(ERROR_CODES.RootNotAllowed, `Root '${root}' is not allowed.`, "Use one of the allowed roots.");
}
// Validate relativePath
if (path.isAbsolute(relativePath)) {
throw new ToolError(ERROR_CODES.PathTraversalDetected, "Path must be relative.", "Provide a relative path from the root.");
}
// Check for drive letter or UNC path in relativePath (extra safety)
if (relativePath.match(/^[a-zA-Z]:/) || relativePath.startsWith('\\\\')) {
throw new ToolError(ERROR_CODES.PathTraversalDetected, "Path must be relative (no drive/UNC).", "Provide a relative path from the root.");
}
const resolvedPath = path.resolve(resolvedRoot, relativePath);
// Check for traversal
const rel = path.relative(resolvedRoot, resolvedPath);
if (rel.startsWith('..') || path.isAbsolute(rel)) {
throw new ToolError(ERROR_CODES.PathTraversalDetected, "Path traversal detected.", "Do not use '..' to escape the root.");
}
return resolvedPath;
}