diff --git a/README.md b/README.md index 3eac28c..aa8f650 100644 --- a/README.md +++ b/README.md @@ -142,6 +142,7 @@ Unlike `VM`, `NodeVM` allows you to require modules in the same way that you wou * `require.root` - Restricted path(s) where local modules can be required (default: every path). * `require.mock` - Collection of mock modules (both external or built-in). * `require.context` - `host` (default) to require modules in the host and proxy them into the sandbox. `sandbox` to load, compile, and require modules in the sandbox. Except for `events`, built-in modules are always required in the host and proxied into the sandbox. +* `require.pathContext` - A callback allowing custom context to be determined per module. Parameters are the module name, and extension. The callback must return `host` or `sandbox` as per above. * `require.import` - An array of modules to be loaded into NodeVM on start. * `require.resolve` - An additional lookup function in case a module wasn't found in one of the traditional node lookup paths. * `require.customRequire` - Use instead of the `require` function to load modules from the host. diff --git a/lib/nodevm.js b/lib/nodevm.js index a55a0e2..488f34b 100644 --- a/lib/nodevm.js +++ b/lib/nodevm.js @@ -17,6 +17,17 @@ * @return {*} The required module object. */ +/** + * This callback will be called to specify the context to use "per" module. + * + * NOTE: many interoperating modules must live in the same context. + * + * @callback pathContextCallback + * @param {string} moduleName - Name of the module requested. + * @param {string} extensionType - The type of extension (node, js, json) + * @return {("host"|"sandbox")} The context for this module. + */ + const fs = require('fs'); const pa = require('path'); const { @@ -180,11 +191,13 @@ class NodeVM extends VM { * @param {("host"|"sandbox")} [options.require.context="host"] - host to require modules in host and proxy them to sandbox. * sandbox to load, compile and require modules in sandbox. * Builtin modules except events always required in host and proxied to sandbox. + * @param {pathContextCallback} [options.require.pathContext] - A callback per-module path to customize "where" to load a module. + * Builtin modules except events always required in host and proxied to sandbox. * @param {string[]} [options.require.import] - Array of modules to be loaded into NodeVM on start. * @param {resolveCallback} [options.require.resolve] - An additional lookup function in case a module wasn't * found in one of the traditional node lookup paths. * @param {customRequire} [options.require.customRequire=require] - Custom require to require host and built-in modules. - * @param {boolean} [option.require.strict=true] - Load required modules in strict mode. + * @param {boolean} [options.require.strict=true] - Load required modules in strict mode. * @param {boolean} [options.nesting=false] - * WARNING: Allowing this is a security risk as scripts can create a NodeVM which can require any host module. * Allow nesting of VMs. diff --git a/lib/resolver-compat.js b/lib/resolver-compat.js index 0ef30ee..2780b67 100644 --- a/lib/resolver-compat.js +++ b/lib/resolver-compat.js @@ -291,6 +291,8 @@ function resolverFromOptions(vm, options, override, compiler) { const builtins = genBuiltinsFromOptions(vm, builtinOpt, mockOpt, override); + const pathContext = options.pathContext || (() => context); + if (!externalOpt) return new Resolver(fsOpt, builtins, [], hostRequire); let checkPath; @@ -344,7 +346,7 @@ function resolverFromOptions(vm, options, override, compiler) { transitive = context === 'sandbox' && externalOpt.transitive; } externals = external.map(makeExternalMatcher); - return new LegacyResolver(fsOpt, builtins, checkPath, [], () => context, newCustomResolver, hostRequire, compiler, strict, externals, transitive); + return new LegacyResolver(fsOpt, builtins, checkPath, [], pathContext, newCustomResolver, hostRequire, compiler, strict, externals, transitive); } exports.resolverFromOptions = resolverFromOptions; diff --git a/package-lock.json b/package-lock.json index 5e61b0d..f4e8dd5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "vm2", - "version": "3.9.11", + "version": "3.9.16", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "vm2", - "version": "3.9.11", + "version": "3.9.16", "license": "MIT", "dependencies": { "acorn": "^8.7.0",