simple-task-master
Version:
A simple command-line task management tool
106 lines • 5.04 kB
JavaScript
;
/**
* Path validation utilities for STM
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateTasksDir = validateTasksDir;
const path = __importStar(require("path"));
const fs = __importStar(require("fs"));
const errors_1 = require("./errors");
/**
* Validates the custom tasks directory path
* @param tasksDir - The proposed tasks directory path
* @returns The normalized tasks directory path
* @throws ValidationError if the path is invalid
*/
function validateTasksDir(tasksDir) {
// Prevent directory traversal attacks - check before normalization
if (tasksDir.includes('..')) {
throw new errors_1.ValidationError('Tasks directory path cannot contain directory traversal sequences (..)');
}
// Normalize the path and remove trailing slashes
const normalized = path.normalize(tasksDir).replace(/\/+$/, '');
// Prevent absolute paths outside the project
if (path.isAbsolute(normalized)) {
// Allow absolute paths only if they're not system directories
// For shared directories, we'll be more permissive and allow sibling directories
// First, check if it's a system directory (but allow temp directories for testing)
const isTempDir = normalized.includes('/tmp/') ||
normalized.includes('\\Temp\\') ||
normalized.includes('\\TEMP\\') ||
normalized.includes('/var/folders/') || // macOS temp directories
normalized.includes('/private/var/folders/'); // macOS private temp
const systemPaths = ['/', '/etc', '/usr', '/bin', '/sbin', '/dev', '/proc', '/sys'];
const isSystemPath = systemPaths.some((sysPath) => normalized === sysPath || normalized.startsWith(sysPath + path.sep));
if (isSystemPath && !isTempDir) {
throw new errors_1.ValidationError('Cannot use system directories for task storage');
}
// For non-system paths, allow more flexibility for shared directories
// Only reject if the path is clearly outside any reasonable project structure
const cwd = fs.realpathSync(process.cwd());
try {
// Try to find a common root between cwd and the target path
const normalizedDir = path.dirname(normalized);
let resolvedDir;
try {
resolvedDir = fs.realpathSync(normalizedDir);
}
catch {
resolvedDir = path.resolve(normalizedDir);
}
const resolvedPath = path.join(resolvedDir, path.basename(normalized));
// Calculate relative path from cwd to target
const relative = path.relative(cwd, resolvedPath);
// Allow paths that go up but not too far (max 5 levels up for shared directories)
const upLevels = relative.split(path.sep).filter((part) => part === '..').length;
if (upLevels > 5) {
throw new errors_1.ValidationError('Absolute paths too far outside the project directory');
}
}
catch {
// If we can't resolve paths, be conservative and reject
throw new errors_1.ValidationError('Invalid absolute path for task storage');
}
}
// Ensure the path doesn't point to a file
// We'll check this during actual creation, but validate obvious cases
if (normalized.includes('.') &&
(normalized.endsWith('.json') || normalized.endsWith('.md') || normalized.endsWith('.txt'))) {
throw new errors_1.ValidationError('Tasks directory path appears to be a file, not a directory');
}
return normalized;
}
//# sourceMappingURL=path-validation.js.map