@dollhousemcp/mcp-server
Version:
DollhouseMCP - A Model Context Protocol (MCP) server that enables dynamic AI persona management from markdown files, allowing Claude and other compatible AI assistants to activate and switch between different behavioral personas.
30 lines • 4.17 kB
JavaScript
import * as path from 'node:path';
/**
* Resolve a target path and verify that it remains inside the intended base
* directory. This is separator-aware, so sibling paths such as `/tmp/base2`
* are not treated as children of `/tmp/base`.
*/
export function resolvePathWithinBase(baseDir, ...segments) {
if (!baseDir || typeof baseDir !== 'string') {
throw new TypeError('Base directory must be a non-empty string');
}
for (const segment of segments) {
if (typeof segment !== 'string') {
throw new TypeError('Path segments must be strings');
}
if (segment.includes('\0')) {
throw new Error('Path segment contains a null byte');
}
}
const resolvedBase = path.resolve(baseDir);
const resolvedTarget = path.resolve(resolvedBase, ...segments);
const relativePath = path.relative(resolvedBase, resolvedTarget);
const isTraversal = relativePath === '..'
|| relativePath.startsWith('..' + path.sep)
|| path.isAbsolute(relativePath);
if (!isTraversal) {
return resolvedTarget;
}
throw new Error('Resolved path escapes the base directory');
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGF0aFNlY3VyaXR5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWxzL3BhdGhTZWN1cml0eS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssSUFBSSxNQUFNLFdBQVcsQ0FBQztBQUVsQzs7OztHQUlHO0FBQ0gsTUFBTSxVQUFVLHFCQUFxQixDQUFDLE9BQWUsRUFBRSxHQUFHLFFBQWtCO0lBQzFFLElBQUksQ0FBQyxPQUFPLElBQUksT0FBTyxPQUFPLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDNUMsTUFBTSxJQUFJLFNBQVMsQ0FBQywyQ0FBMkMsQ0FBQyxDQUFDO0lBQ25FLENBQUM7SUFFRCxLQUFLLE1BQU0sT0FBTyxJQUFJLFFBQVEsRUFBRSxDQUFDO1FBQy9CLElBQUksT0FBTyxPQUFPLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDaEMsTUFBTSxJQUFJLFNBQVMsQ0FBQywrQkFBK0IsQ0FBQyxDQUFDO1FBQ3ZELENBQUM7UUFDRCxJQUFJLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztZQUMzQixNQUFNLElBQUksS0FBSyxDQUFDLG1DQUFtQyxDQUFDLENBQUM7UUFDdkQsQ0FBQztJQUNILENBQUM7SUFFRCxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQzNDLE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsWUFBWSxFQUFFLEdBQUcsUUFBUSxDQUFDLENBQUM7SUFDL0QsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxZQUFZLEVBQUUsY0FBYyxDQUFDLENBQUM7SUFDakUsTUFBTSxXQUFXLEdBQUcsWUFBWSxLQUFLLElBQUk7V0FDcEMsWUFBWSxDQUFDLFVBQVUsQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQztXQUN4QyxJQUFJLENBQUMsVUFBVSxDQUFDLFlBQVksQ0FBQyxDQUFDO0lBRW5DLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUNqQixPQUFPLGNBQWMsQ0FBQztJQUN4QixDQUFDO0lBRUQsTUFBTSxJQUFJLEtBQUssQ0FBQywwQ0FBMEMsQ0FBQyxDQUFDO0FBQzlELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBwYXRoIGZyb20gJ25vZGU6cGF0aCc7XG5cbi8qKlxuICogUmVzb2x2ZSBhIHRhcmdldCBwYXRoIGFuZCB2ZXJpZnkgdGhhdCBpdCByZW1haW5zIGluc2lkZSB0aGUgaW50ZW5kZWQgYmFzZVxuICogZGlyZWN0b3J5LiBUaGlzIGlzIHNlcGFyYXRvci1hd2FyZSwgc28gc2libGluZyBwYXRocyBzdWNoIGFzIGAvdG1wL2Jhc2UyYFxuICogYXJlIG5vdCB0cmVhdGVkIGFzIGNoaWxkcmVuIG9mIGAvdG1wL2Jhc2VgLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZVBhdGhXaXRoaW5CYXNlKGJhc2VEaXI6IHN0cmluZywgLi4uc2VnbWVudHM6IHN0cmluZ1tdKTogc3RyaW5nIHtcbiAgaWYgKCFiYXNlRGlyIHx8IHR5cGVvZiBiYXNlRGlyICE9PSAnc3RyaW5nJykge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0Jhc2UgZGlyZWN0b3J5IG11c3QgYmUgYSBub24tZW1wdHkgc3RyaW5nJyk7XG4gIH1cblxuICBmb3IgKGNvbnN0IHNlZ21lbnQgb2Ygc2VnbWVudHMpIHtcbiAgICBpZiAodHlwZW9mIHNlZ21lbnQgIT09ICdzdHJpbmcnKSB7XG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdQYXRoIHNlZ21lbnRzIG11c3QgYmUgc3RyaW5ncycpO1xuICAgIH1cbiAgICBpZiAoc2VnbWVudC5pbmNsdWRlcygnXFwwJykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignUGF0aCBzZWdtZW50IGNvbnRhaW5zIGEgbnVsbCBieXRlJyk7XG4gICAgfVxuICB9XG5cbiAgY29uc3QgcmVzb2x2ZWRCYXNlID0gcGF0aC5yZXNvbHZlKGJhc2VEaXIpO1xuICBjb25zdCByZXNvbHZlZFRhcmdldCA9IHBhdGgucmVzb2x2ZShyZXNvbHZlZEJhc2UsIC4uLnNlZ21lbnRzKTtcbiAgY29uc3QgcmVsYXRpdmVQYXRoID0gcGF0aC5yZWxhdGl2ZShyZXNvbHZlZEJhc2UsIHJlc29sdmVkVGFyZ2V0KTtcbiAgY29uc3QgaXNUcmF2ZXJzYWwgPSByZWxhdGl2ZVBhdGggPT09ICcuLidcbiAgICB8fCByZWxhdGl2ZVBhdGguc3RhcnRzV2l0aCgnLi4nICsgcGF0aC5zZXApXG4gICAgfHwgcGF0aC5pc0Fic29sdXRlKHJlbGF0aXZlUGF0aCk7XG5cbiAgaWYgKCFpc1RyYXZlcnNhbCkge1xuICAgIHJldHVybiByZXNvbHZlZFRhcmdldDtcbiAgfVxuXG4gIHRocm93IG5ldyBFcnJvcignUmVzb2x2ZWQgcGF0aCBlc2NhcGVzIHRoZSBiYXNlIGRpcmVjdG9yeScpO1xufVxuIl19