UNPKG

projen

Version:

CDK for software projects

109 lines • 12.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ensureRelativePathStartsWithDot = ensureRelativePathStartsWithDot; exports.isHiddenPath = isHiddenPath; exports.ensureNotHiddenPath = ensureNotHiddenPath; exports.isPathInside = isPathInside; exports.realpathOfClosestExisting = realpathOfClosestExisting; exports.ensurePathInsideProject = ensurePathInsideProject; const node_fs_1 = require("node:fs"); const node_path_1 = require("node:path"); /** * Helper function to format a path as dot notation regardless of how it * was handed in. * * @param path - can be formatted as "path", "./path" (but not "/path", as it is absolute) * @returns "./path" */ function ensureRelativePathStartsWithDot(path) { if (path.startsWith(".")) { return path; } if (path.startsWith("/")) { throw new Error(`Path ${path} must be relative`); } return `./${path}`; } /** * Checks if part of the file path is hidden */ function isHiddenPath(path) { return /(^|\/)\.[^\/\.]/g.test(path); } /** * Helper to assert a path is not hidden */ function ensureNotHiddenPath(value, name) { if (isHiddenPath(value)) { throw Error(`${name} cannot be a hidden path, got: ${value}`); } } /** * Checks if `file` is strictly inside `dir` (the directory itself does not count). * * Purely lexical: does not consult the filesystem, so symlinks are not * resolved. Relative paths are resolved against the current working directory. */ function isPathInside(dir, file) { const rel = (0, node_path_1.relative)(dir, file); return (rel !== "" && !rel.startsWith(`..${node_path_1.sep}`) && rel !== ".." && !(0, node_path_1.isAbsolute)(rel)); } /** * Resolves symlinks in `p`, falling back to the closest existing ancestor for * paths that do not exist (yet). */ function realpathOfClosestExisting(p) { const missing = new Array(); let current = (0, node_path_1.resolve)(p); while (true) { try { return (0, node_path_1.join)((0, node_fs_1.realpathSync)(current), ...missing); } catch { const parent = (0, node_path_1.dirname)(current); if (parent === current) { return (0, node_path_1.resolve)(p); } missing.unshift((0, node_path_1.basename)(current)); current = parent; } } } /** * Asserts that a path stays strictly inside a project directory. * * Use this before passing a user-configurable path to a destructive command * (e.g. `rm -fr`): an absolute path or a path traversing outside of the * project directory (via `..` or a symlink) could otherwise delete files * anywhere on the machine. The project directory itself (`.`) is also * rejected. * * The check resolves both paths on the filesystem (symlinks in existing path * segments are followed). The last segment of the path is intentionally kept * as-is: a symlink inside the project only affects the link itself. * * @param value the path to check, relative to the project directory * @param name name of the option, used in the error message * @param projectDir the project directory the path must stay inside of * @throws if the path is absolute or does not stay inside the project directory */ function ensurePathInsideProject(value, name, projectDir) { if ((0, node_path_1.isAbsolute)(value)) { throw new Error(`${name} must be a relative path within the project directory, got absolute path: ${value}`); } const baseDir = realpathOfClosestExisting(projectDir); const resolved = (0, node_path_1.resolve)(baseDir, value); if (!isPathInside(baseDir, resolved)) { throw new Error(`${name} must be inside the project directory, got: ${value}`); } // the path might traverse outside of the project through a symlinked // directory, which a lexical `resolve` cannot detect const realParent = realpathOfClosestExisting((0, node_path_1.dirname)(resolved)); if (!isPathInside(baseDir, (0, node_path_1.join)(realParent, (0, node_path_1.basename)(resolved)))) { throw new Error(`${name} must be inside the project directory, but points outside of it through a symlink, got: ${value}`); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGF0aC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlsL3BhdGgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFrQkEsMEVBVUM7QUFLRCxvQ0FFQztBQUtELGtEQUlDO0FBUUQsb0NBUUM7QUFNRCw4REFnQkM7QUFvQkQsMERBNEJDO0FBbElELHFDQUF1QztBQUN2Qyx5Q0FRbUI7QUFFbkI7Ozs7OztHQU1HO0FBQ0gsU0FBZ0IsK0JBQStCLENBQUMsSUFBWTtJQUMxRCxJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUN6QixPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRCxJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUN6QixNQUFNLElBQUksS0FBSyxDQUFDLFFBQVEsSUFBSSxtQkFBbUIsQ0FBQyxDQUFDO0lBQ25ELENBQUM7SUFFRCxPQUFPLEtBQUssSUFBSSxFQUFFLENBQUM7QUFDckIsQ0FBQztBQUVEOztHQUVHO0FBQ0gsU0FBZ0IsWUFBWSxDQUFDLElBQVk7SUFDdkMsT0FBTyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7QUFDdkMsQ0FBQztBQUVEOztHQUVHO0FBQ0gsU0FBZ0IsbUJBQW1CLENBQUMsS0FBYSxFQUFFLElBQVk7SUFDN0QsSUFBSSxZQUFZLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztRQUN4QixNQUFNLEtBQUssQ0FBQyxHQUFHLElBQUksa0NBQWtDLEtBQUssRUFBRSxDQUFDLENBQUM7SUFDaEUsQ0FBQztBQUNILENBQUM7QUFFRDs7Ozs7R0FLRztBQUNILFNBQWdCLFlBQVksQ0FBQyxHQUFXLEVBQUUsSUFBWTtJQUNwRCxNQUFNLEdBQUcsR0FBRyxJQUFBLG9CQUFRLEVBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQ2hDLE9BQU8sQ0FDTCxHQUFHLEtBQUssRUFBRTtRQUNWLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxLQUFLLGVBQUcsRUFBRSxDQUFDO1FBQzNCLEdBQUcsS0FBSyxJQUFJO1FBQ1osQ0FBQyxJQUFBLHNCQUFVLEVBQUMsR0FBRyxDQUFDLENBQ2pCLENBQUM7QUFDSixDQUFDO0FBRUQ7OztHQUdHO0FBQ0gsU0FBZ0IseUJBQXlCLENBQUMsQ0FBUztJQUNqRCxNQUFNLE9BQU8sR0FBRyxJQUFJLEtBQUssRUFBVSxDQUFDO0lBQ3BDLElBQUksT0FBTyxHQUFHLElBQUEsbUJBQU8sRUFBQyxDQUFDLENBQUMsQ0FBQztJQUV6QixPQUFPLElBQUksRUFBRSxDQUFDO1FBQ1osSUFBSSxDQUFDO1lBQ0gsT0FBTyxJQUFBLGdCQUFJLEVBQUMsSUFBQSxzQkFBWSxFQUFDLE9BQU8sQ0FBQyxFQUFFLEdBQUcsT0FBTyxDQUFDLENBQUM7UUFDakQsQ0FBQztRQUFDLE1BQU0sQ0FBQztZQUNQLE1BQU0sTUFBTSxHQUFHLElBQUEsbUJBQU8sRUFBQyxPQUFPLENBQUMsQ0FBQztZQUNoQyxJQUFJLE1BQU0sS0FBSyxPQUFPLEVBQUUsQ0FBQztnQkFDdkIsT0FBTyxJQUFBLG1CQUFPLEVBQUMsQ0FBQyxDQUFDLENBQUM7WUFDcEIsQ0FBQztZQUNELE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBQSxvQkFBUSxFQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUM7WUFDbkMsT0FBTyxHQUFHLE1BQU0sQ0FBQztRQUNuQixDQUFDO0lBQ0gsQ0FBQztBQUNILENBQUM7QUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FpQkc7QUFDSCxTQUFnQix1QkFBdUIsQ0FDckMsS0FBYSxFQUNiLElBQVksRUFDWixVQUFrQjtJQUVsQixJQUFJLElBQUEsc0JBQVUsRUFBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQ3RCLE1BQU0sSUFBSSxLQUFLLENBQ2IsR0FBRyxJQUFJLDZFQUE2RSxLQUFLLEVBQUUsQ0FDNUYsQ0FBQztJQUNKLENBQUM7SUFFRCxNQUFNLE9BQU8sR0FBRyx5QkFBeUIsQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUN0RCxNQUFNLFFBQVEsR0FBRyxJQUFBLG1CQUFPLEVBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBRXpDLElBQUksQ0FBQyxZQUFZLENBQUMsT0FBTyxFQUFFLFFBQVEsQ0FBQyxFQUFFLENBQUM7UUFDckMsTUFBTSxJQUFJLEtBQUssQ0FDYixHQUFHLElBQUksK0NBQStDLEtBQUssRUFBRSxDQUM5RCxDQUFDO0lBQ0osQ0FBQztJQUVELHFFQUFxRTtJQUNyRSxxREFBcUQ7SUFDckQsTUFBTSxVQUFVLEdBQUcseUJBQXlCLENBQUMsSUFBQSxtQkFBTyxFQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUM7SUFDaEUsSUFBSSxDQUFDLFlBQVksQ0FBQyxPQUFPLEVBQUUsSUFBQSxnQkFBSSxFQUFDLFVBQVUsRUFBRSxJQUFBLG9CQUFRLEVBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDakUsTUFBTSxJQUFJLEtBQUssQ0FDYixHQUFHLElBQUksMkZBQTJGLEtBQUssRUFBRSxDQUMxRyxDQUFDO0lBQ0osQ0FBQztBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyByZWFscGF0aFN5bmMgfSBmcm9tIFwibm9kZTpmc1wiO1xuaW1wb3J0IHtcbiAgYmFzZW5hbWUsXG4gIGRpcm5hbWUsXG4gIGlzQWJzb2x1dGUsXG4gIGpvaW4sXG4gIHJlbGF0aXZlLFxuICByZXNvbHZlLFxuICBzZXAsXG59IGZyb20gXCJub2RlOnBhdGhcIjtcblxuLyoqXG4gKiBIZWxwZXIgZnVuY3Rpb24gdG8gZm9ybWF0IGEgcGF0aCBhcyBkb3Qgbm90YXRpb24gcmVnYXJkbGVzcyBvZiBob3cgaXRcbiAqIHdhcyBoYW5kZWQgaW4uXG4gKlxuICogQHBhcmFtIHBhdGggLSBjYW4gYmUgZm9ybWF0dGVkIGFzIFwicGF0aFwiLCBcIi4vcGF0aFwiIChidXQgbm90IFwiL3BhdGhcIiwgYXMgaXQgaXMgYWJzb2x1dGUpXG4gKiBAcmV0dXJucyBcIi4vcGF0aFwiXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBlbnN1cmVSZWxhdGl2ZVBhdGhTdGFydHNXaXRoRG90KHBhdGg6IHN0cmluZyk6IHN0cmluZyB7XG4gIGlmIChwYXRoLnN0YXJ0c1dpdGgoXCIuXCIpKSB7XG4gICAgcmV0dXJuIHBhdGg7XG4gIH1cblxuICBpZiAocGF0aC5zdGFydHNXaXRoKFwiL1wiKSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgUGF0aCAke3BhdGh9IG11c3QgYmUgcmVsYXRpdmVgKTtcbiAgfVxuXG4gIHJldHVybiBgLi8ke3BhdGh9YDtcbn1cblxuLyoqXG4gKiBDaGVja3MgaWYgcGFydCBvZiB0aGUgZmlsZSBwYXRoIGlzIGhpZGRlblxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNIaWRkZW5QYXRoKHBhdGg6IHN0cmluZykge1xuICByZXR1cm4gLyhefFxcLylcXC5bXlxcL1xcLl0vZy50ZXN0KHBhdGgpO1xufVxuXG4vKipcbiAqIEhlbHBlciB0byBhc3NlcnQgYSBwYXRoIGlzIG5vdCBoaWRkZW5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGVuc3VyZU5vdEhpZGRlblBhdGgodmFsdWU6IHN0cmluZywgbmFtZTogc3RyaW5nKSB7XG4gIGlmIChpc0hpZGRlblBhdGgodmFsdWUpKSB7XG4gICAgdGhyb3cgRXJyb3IoYCR7bmFtZX0gY2Fubm90IGJlIGEgaGlkZGVuIHBhdGgsIGdvdDogJHt2YWx1ZX1gKTtcbiAgfVxufVxuXG4vKipcbiAqIENoZWNrcyBpZiBgZmlsZWAgaXMgc3RyaWN0bHkgaW5zaWRlIGBkaXJgICh0aGUgZGlyZWN0b3J5IGl0c2VsZiBkb2VzIG5vdCBjb3VudCkuXG4gKlxuICogUHVyZWx5IGxleGljYWw6IGRvZXMgbm90IGNvbnN1bHQgdGhlIGZpbGVzeXN0ZW0sIHNvIHN5bWxpbmtzIGFyZSBub3RcbiAqIHJlc29sdmVkLiBSZWxhdGl2ZSBwYXRocyBhcmUgcmVzb2x2ZWQgYWdhaW5zdCB0aGUgY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzUGF0aEluc2lkZShkaXI6IHN0cmluZywgZmlsZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gIGNvbnN0IHJlbCA9IHJlbGF0aXZlKGRpciwgZmlsZSk7XG4gIHJldHVybiAoXG4gICAgcmVsICE9PSBcIlwiICYmXG4gICAgIXJlbC5zdGFydHNXaXRoKGAuLiR7c2VwfWApICYmXG4gICAgcmVsICE9PSBcIi4uXCIgJiZcbiAgICAhaXNBYnNvbHV0ZShyZWwpXG4gICk7XG59XG5cbi8qKlxuICogUmVzb2x2ZXMgc3ltbGlua3MgaW4gYHBgLCBmYWxsaW5nIGJhY2sgdG8gdGhlIGNsb3Nlc3QgZXhpc3RpbmcgYW5jZXN0b3IgZm9yXG4gKiBwYXRocyB0aGF0IGRvIG5vdCBleGlzdCAoeWV0KS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlYWxwYXRoT2ZDbG9zZXN0RXhpc3RpbmcocDogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3QgbWlzc2luZyA9IG5ldyBBcnJheTxzdHJpbmc+KCk7XG4gIGxldCBjdXJyZW50ID0gcmVzb2x2ZShwKTtcblxuICB3aGlsZSAodHJ1ZSkge1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gam9pbihyZWFscGF0aFN5bmMoY3VycmVudCksIC4uLm1pc3NpbmcpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgY29uc3QgcGFyZW50ID0gZGlybmFtZShjdXJyZW50KTtcbiAgICAgIGlmIChwYXJlbnQgPT09IGN1cnJlbnQpIHtcbiAgICAgICAgcmV0dXJuIHJlc29sdmUocCk7XG4gICAgICB9XG4gICAgICBtaXNzaW5nLnVuc2hpZnQoYmFzZW5hbWUoY3VycmVudCkpO1xuICAgICAgY3VycmVudCA9IHBhcmVudDtcbiAgICB9XG4gIH1cbn1cblxuLyoqXG4gKiBBc3NlcnRzIHRoYXQgYSBwYXRoIHN0YXlzIHN0cmljdGx5IGluc2lkZSBhIHByb2plY3QgZGlyZWN0b3J5LlxuICpcbiAqIFVzZSB0aGlzIGJlZm9yZSBwYXNzaW5nIGEgdXNlci1jb25maWd1cmFibGUgcGF0aCB0byBhIGRlc3RydWN0aXZlIGNvbW1hbmRcbiAqIChlLmcuIGBybSAtZnJgKTogYW4gYWJzb2x1dGUgcGF0aCBvciBhIHBhdGggdHJhdmVyc2luZyBvdXRzaWRlIG9mIHRoZVxuICogcHJvamVjdCBkaXJlY3RvcnkgKHZpYSBgLi5gIG9yIGEgc3ltbGluaykgY291bGQgb3RoZXJ3aXNlIGRlbGV0ZSBmaWxlc1xuICogYW55d2hlcmUgb24gdGhlIG1hY2hpbmUuIFRoZSBwcm9qZWN0IGRpcmVjdG9yeSBpdHNlbGYgKGAuYCkgaXMgYWxzb1xuICogcmVqZWN0ZWQuXG4gKlxuICogVGhlIGNoZWNrIHJlc29sdmVzIGJvdGggcGF0aHMgb24gdGhlIGZpbGVzeXN0ZW0gKHN5bWxpbmtzIGluIGV4aXN0aW5nIHBhdGhcbiAqIHNlZ21lbnRzIGFyZSBmb2xsb3dlZCkuIFRoZSBsYXN0IHNlZ21lbnQgb2YgdGhlIHBhdGggaXMgaW50ZW50aW9uYWxseSBrZXB0XG4gKiBhcy1pczogYSBzeW1saW5rIGluc2lkZSB0aGUgcHJvamVjdCBvbmx5IGFmZmVjdHMgdGhlIGxpbmsgaXRzZWxmLlxuICpcbiAqIEBwYXJhbSB2YWx1ZSB0aGUgcGF0aCB0byBjaGVjaywgcmVsYXRpdmUgdG8gdGhlIHByb2plY3QgZGlyZWN0b3J5XG4gKiBAcGFyYW0gbmFtZSBuYW1lIG9mIHRoZSBvcHRpb24sIHVzZWQgaW4gdGhlIGVycm9yIG1lc3NhZ2VcbiAqIEBwYXJhbSBwcm9qZWN0RGlyIHRoZSBwcm9qZWN0IGRpcmVjdG9yeSB0aGUgcGF0aCBtdXN0IHN0YXkgaW5zaWRlIG9mXG4gKiBAdGhyb3dzIGlmIHRoZSBwYXRoIGlzIGFic29sdXRlIG9yIGRvZXMgbm90IHN0YXkgaW5zaWRlIHRoZSBwcm9qZWN0IGRpcmVjdG9yeVxuICovXG5leHBvcnQgZnVuY3Rpb24gZW5zdXJlUGF0aEluc2lkZVByb2plY3QoXG4gIHZhbHVlOiBzdHJpbmcsXG4gIG5hbWU6IHN0cmluZyxcbiAgcHJvamVjdERpcjogc3RyaW5nLFxuKSB7XG4gIGlmIChpc0Fic29sdXRlKHZhbHVlKSkge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGAke25hbWV9IG11c3QgYmUgYSByZWxhdGl2ZSBwYXRoIHdpdGhpbiB0aGUgcHJvamVjdCBkaXJlY3RvcnksIGdvdCBhYnNvbHV0ZSBwYXRoOiAke3ZhbHVlfWAsXG4gICAgKTtcbiAgfVxuXG4gIGNvbnN0IGJhc2VEaXIgPSByZWFscGF0aE9mQ2xvc2VzdEV4aXN0aW5nKHByb2plY3REaXIpO1xuICBjb25zdCByZXNvbHZlZCA9IHJlc29sdmUoYmFzZURpciwgdmFsdWUpO1xuXG4gIGlmICghaXNQYXRoSW5zaWRlKGJhc2VEaXIsIHJlc29sdmVkKSkge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGAke25hbWV9IG11c3QgYmUgaW5zaWRlIHRoZSBwcm9qZWN0IGRpcmVjdG9yeSwgZ290OiAke3ZhbHVlfWAsXG4gICAgKTtcbiAgfVxuXG4gIC8vIHRoZSBwYXRoIG1pZ2h0IHRyYXZlcnNlIG91dHNpZGUgb2YgdGhlIHByb2plY3QgdGhyb3VnaCBhIHN5bWxpbmtlZFxuICAvLyBkaXJlY3RvcnksIHdoaWNoIGEgbGV4aWNhbCBgcmVzb2x2ZWAgY2Fubm90IGRldGVjdFxuICBjb25zdCByZWFsUGFyZW50ID0gcmVhbHBhdGhPZkNsb3Nlc3RFeGlzdGluZyhkaXJuYW1lKHJlc29sdmVkKSk7XG4gIGlmICghaXNQYXRoSW5zaWRlKGJhc2VEaXIsIGpvaW4ocmVhbFBhcmVudCwgYmFzZW5hbWUocmVzb2x2ZWQpKSkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgJHtuYW1lfSBtdXN0IGJlIGluc2lkZSB0aGUgcHJvamVjdCBkaXJlY3RvcnksIGJ1dCBwb2ludHMgb3V0c2lkZSBvZiBpdCB0aHJvdWdoIGEgc3ltbGluaywgZ290OiAke3ZhbHVlfWAsXG4gICAgKTtcbiAgfVxufVxuIl19