From dde59fc9334a9694c3df52d65fdaa24786ae3e1c Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 8 May 2019 13:42:22 -0400 Subject: [PATCH] module: improve resolve paths validation This commit adds input validation to require.resolve()'s paths option. Prior to this change, passing in a non-array value lead to a misleading 'module not found' error. Refs: https://github.com/nodejs/node/issues/27583 --- lib/internal/modules/cjs/loader.js | 38 +++++++++++++++++------------- test/fixtures/require-resolve.js | 8 +++++++ 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index d02c632bcee5a7..43cffd89cb819d 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -53,6 +53,7 @@ const { compileFunction } = internalBinding('contextify'); const { ERR_INVALID_ARG_VALUE, + ERR_INVALID_OPT_VALUE, ERR_REQUIRE_ESM } = require('internal/errors').codes; const { validateString } = require('internal/validators'); @@ -573,28 +574,33 @@ Module._resolveFilename = function(request, parent, isMain, options) { var paths; - if (typeof options === 'object' && options !== null && - Array.isArray(options.paths)) { - const isRelative = request.startsWith('./') || request.startsWith('../') || - (isWindows && request.startsWith('.\\') || request.startsWith('..\\')); + if (typeof options === 'object' && options !== null) { + if (Array.isArray(options.paths)) { + const isRelative = request.startsWith('./') || + request.startsWith('../') || + (isWindows && request.startsWith('.\\') || + request.startsWith('..\\')); - if (isRelative) { - paths = options.paths; - } else { - const fakeParent = new Module('', null); + if (isRelative) { + paths = options.paths; + } else { + const fakeParent = new Module('', null); - paths = []; + paths = []; - for (var i = 0; i < options.paths.length; i++) { - const path = options.paths[i]; - fakeParent.paths = Module._nodeModulePaths(path); - const lookupPaths = Module._resolveLookupPaths(request, fakeParent); + for (var i = 0; i < options.paths.length; i++) { + const path = options.paths[i]; + fakeParent.paths = Module._nodeModulePaths(path); + const lookupPaths = Module._resolveLookupPaths(request, fakeParent); - for (var j = 0; j < lookupPaths.length; j++) { - if (!paths.includes(lookupPaths[j])) - paths.push(lookupPaths[j]); + for (var j = 0; j < lookupPaths.length; j++) { + if (!paths.includes(lookupPaths[j])) + paths.push(lookupPaths[j]); + } } } + } else if (options.paths !== undefined) { + throw new ERR_INVALID_OPT_VALUE('options.paths', options.paths); } } else { paths = Module._resolveLookupPaths(request, parent); diff --git a/test/fixtures/require-resolve.js b/test/fixtures/require-resolve.js index a398e59cfa496f..3d8500e5097a70 100644 --- a/test/fixtures/require-resolve.js +++ b/test/fixtures/require-resolve.js @@ -84,3 +84,11 @@ assert.throws(() => { ); } } + +// Test paths option validation +common.expectsError(() => { + require.resolve('.\\three.js', { paths: 'foo' }) +}, { + code: 'ERR_INVALID_OPT_VALUE', + type: TypeError, +});