mirror of
https://github.com/modelcontextprotocol/servers.git
synced 2026-02-19 11:54:58 -05:00
* fix: comprehensive Windows path handling improvements - Add path-utils module for consistent path handling - Handle Windows paths with spaces via proper quoting - Support Unix-style Windows paths (/c/path) - Support WSL paths (/mnt/c/path) - Add comprehensive test coverage - Fix path normalization for all path formats Closes #447 * tested locally and working now * Add filesystem path utils and tests * Ensure Windows drive letters are capitalized in normalizePath * adding test for gh pr comment * pushing jest and windows testing config * last commit? fixing comments on PR * Fix bin and bump sdk * Remove redundant commonjs version of path-utils and import from ts version * Remove copying cjs file * Remove copying run-server * Remove complex args parsing and do other cleanup * Add missing tools details to Readme * Move utility functions from index to lib * Add more tests and handle very small and very large files edge cases * Finish refactoring and include original security fix comments * On Windows, also check for drive root * Check symlink support on restricted Windows environments * Fix tests * Bump SDK and package version * Clean up --------- Co-authored-by: olaservo <olahungerford@gmail.com> Co-authored-by: adam jones <adamj+git@anthropic.com>
87 lines
2.7 KiB
TypeScript
87 lines
2.7 KiB
TypeScript
import path from 'path';
|
|
|
|
/**
|
|
* Checks if an absolute path is within any of the allowed directories.
|
|
*
|
|
* @param absolutePath - The absolute path to check (will be normalized)
|
|
* @param allowedDirectories - Array of absolute allowed directory paths (will be normalized)
|
|
* @returns true if the path is within an allowed directory, false otherwise
|
|
* @throws Error if given relative paths after normalization
|
|
*/
|
|
export function isPathWithinAllowedDirectories(absolutePath: string, allowedDirectories: string[]): boolean {
|
|
// Type validation
|
|
if (typeof absolutePath !== 'string' || !Array.isArray(allowedDirectories)) {
|
|
return false;
|
|
}
|
|
|
|
// Reject empty inputs
|
|
if (!absolutePath || allowedDirectories.length === 0) {
|
|
return false;
|
|
}
|
|
|
|
// Reject null bytes (forbidden in paths)
|
|
if (absolutePath.includes('\x00')) {
|
|
return false;
|
|
}
|
|
|
|
// Normalize the input path
|
|
let normalizedPath: string;
|
|
try {
|
|
normalizedPath = path.resolve(path.normalize(absolutePath));
|
|
} catch {
|
|
return false;
|
|
}
|
|
|
|
// Verify it's absolute after normalization
|
|
if (!path.isAbsolute(normalizedPath)) {
|
|
throw new Error('Path must be absolute after normalization');
|
|
}
|
|
|
|
// Check against each allowed directory
|
|
return allowedDirectories.some(dir => {
|
|
if (typeof dir !== 'string' || !dir) {
|
|
return false;
|
|
}
|
|
|
|
// Reject null bytes in allowed dirs
|
|
if (dir.includes('\x00')) {
|
|
return false;
|
|
}
|
|
|
|
// Normalize the allowed directory
|
|
let normalizedDir: string;
|
|
try {
|
|
normalizedDir = path.resolve(path.normalize(dir));
|
|
} catch {
|
|
return false;
|
|
}
|
|
|
|
// Verify allowed directory is absolute after normalization
|
|
if (!path.isAbsolute(normalizedDir)) {
|
|
throw new Error('Allowed directories must be absolute paths after normalization');
|
|
}
|
|
|
|
// Check if normalizedPath is within normalizedDir
|
|
// Path is inside if it's the same or a subdirectory
|
|
if (normalizedPath === normalizedDir) {
|
|
return true;
|
|
}
|
|
|
|
// Special case for root directory to avoid double slash
|
|
// On Windows, we need to check if both paths are on the same drive
|
|
if (normalizedDir === path.sep) {
|
|
return normalizedPath.startsWith(path.sep);
|
|
}
|
|
|
|
// On Windows, also check for drive root (e.g., "C:\")
|
|
if (path.sep === '\\' && normalizedDir.match(/^[A-Za-z]:\\?$/)) {
|
|
// Ensure both paths are on the same drive
|
|
const dirDrive = normalizedDir.charAt(0).toLowerCase();
|
|
const pathDrive = normalizedPath.charAt(0).toLowerCase();
|
|
return pathDrive === dirDrive && normalizedPath.startsWith(normalizedDir.replace(/\\?$/, '\\'));
|
|
}
|
|
|
|
return normalizedPath.startsWith(normalizedDir + path.sep);
|
|
});
|
|
}
|