28 lines
1 KiB
JavaScript
28 lines
1 KiB
JavaScript
import { resolve, extname, sep, isAbsolute } from 'path';
|
|
import { pathToFileURL } from 'url';
|
|
import { rootDir } from '../index.js';
|
|
|
|
/**
|
|
* Securely import a JavaScript module from within the application root.
|
|
* Prevents path traversal and disallows non-.js extensions.
|
|
*
|
|
* @param {string} relPath - The relative path to the module from the application root.
|
|
* @returns {Promise<any>} The imported module.
|
|
*/
|
|
export async function secureImportModule(relPath) {
|
|
if (isAbsolute(relPath)) {
|
|
throw new Error('Absolute paths are not allowed for module imports');
|
|
}
|
|
if (relPath.includes('..')) {
|
|
throw new Error('Relative paths containing .. are not allowed for module imports');
|
|
}
|
|
if (extname(relPath) !== '.js') {
|
|
throw new Error(`Only .js files can be imported: ${relPath}`);
|
|
}
|
|
const absPath = resolve(rootDir, relPath);
|
|
if (!absPath.startsWith(rootDir + sep)) {
|
|
throw new Error(`Module path outside of application root: ${relPath}`);
|
|
}
|
|
const url = pathToFileURL(absPath).href;
|
|
return import(url);
|
|
}
|