Comparing version 3.6.5 to 3.6.6
@@ -0,1 +1,5 @@ | ||
v3.6.6 (2019-01-01) | ||
------------------- | ||
[fix] Security fixes | ||
v3.6.5 (2018-12-31) | ||
@@ -2,0 +6,0 @@ ------------------- |
@@ -31,3 +31,3 @@ import {EventEmitter} from 'events'; | ||
/** | ||
* Options for creating a NodeVM | ||
* Options for creating a VM | ||
*/ | ||
@@ -47,13 +47,10 @@ export interface VMOptions { | ||
timeout?: number; | ||
/** File extensions that the internal module resolver should accept. */ | ||
sourceExtensions?: string[] | ||
} | ||
/** | ||
* Options specific o | ||
* Options for creating a NodeVM | ||
*/ | ||
export interface NodeVMOptions extends VMOptions { | ||
/** `inherit` to enable console, `redirect` to redirect to events, `off` to disable console (default: `inherit`). */ | ||
console?: "inherit" | "redirect"; | ||
console?: "inherit" | "redirect" | "off"; | ||
/** `true` or an object to enable `require` optionss (default: `false`). */ | ||
@@ -64,3 +61,5 @@ require?: true | VMRequire; | ||
/** `commonjs` (default) to wrap script into CommonJS wrapper, `none` to retrieve value returned by the script. */ | ||
wrapper?: "commonjs" | "none"; | ||
wrapper?: "commonjs" | "none"; | ||
/** File extensions that the internal module resolver should accept. */ | ||
sourceExtensions?: string[] | ||
} | ||
@@ -67,0 +66,0 @@ |
if (parseInt(process.versions.node.split('.')[0]) < 6) throw new Error('vm2 requires Node.js version 6 or newer.'); | ||
module.exports = require("./lib/main"); | ||
module.exports = require('./lib/main'); |
@@ -1,2 +0,3 @@ | ||
const fs = require('fs'); | ||
'use strict'; | ||
const pa = require('path'); | ||
@@ -3,0 +4,0 @@ |
@@ -1,5 +0,9 @@ | ||
'use strict' | ||
/* global host */ | ||
/* eslint-disable block-spacing, no-multi-spaces, brace-style, no-array-constructor, new-cap, no-use-before-define */ | ||
'use strict'; | ||
// eslint-disable-next-line no-invalid-this, no-shadow | ||
const global = this; | ||
const console = host.console; | ||
const local = {Object}; | ||
@@ -18,3 +22,3 @@ // global is originally prototype of host.Object so it can be used to climb up from the sandbox. | ||
const OPNA = 'Operation not allowed on contextified object.'; | ||
const ERROR_CST = Error.captureStackTrace; | ||
const captureStackTrace = Error.captureStackTrace; | ||
const FROZEN_TRAPS = { | ||
@@ -27,3 +31,3 @@ set: (target, key) => false, | ||
preventExtensions: (target) => false | ||
} | ||
}; | ||
@@ -34,2 +38,15 @@ // Map of contextified objects to original objects | ||
// Fake setters make sure we use correctly scoped definer for getter/setter definition | ||
function fakeDefineGetter(receiver, useLocalDefiner) { | ||
return function __defineGetter__(key, value) { | ||
(useLocalDefiner ? local.Object : host.Object).defineProperty(receiver, key, {get: value, enumerable: true, configurable: true}); | ||
}; | ||
} | ||
function fakeDefineSetter(receiver, useLocalDefiner) { | ||
return function __defineSetter__(key, value) { | ||
(useLocalDefiner ? local.Object : host.Object).defineProperty(receiver, key, {set: value, enumerable: true, configurable: true}); | ||
}; | ||
} | ||
/** | ||
@@ -39,3 +56,3 @@ * VMError definition. | ||
global.VMError = class VMError extends Error { | ||
class VMError extends Error { | ||
constructor(message, code) { | ||
@@ -47,6 +64,8 @@ super(message); | ||
ERROR_CST(this, this.constructor); | ||
captureStackTrace(this, this.constructor); | ||
} | ||
} | ||
global.VMError = VMError; | ||
/** | ||
@@ -59,3 +78,3 @@ * Decontextify. | ||
arguments: function(args) { | ||
arguments: args => { | ||
if (!host.Array.isArray(args)) return new host.Array(); | ||
@@ -67,3 +86,3 @@ | ||
}, | ||
instance: function(instance, klass, deepTraps, flags) { | ||
instance: (instance, klass, deepTraps, flags) => { | ||
return Decontextify.object(instance, { | ||
@@ -75,2 +94,4 @@ get: (target, key, receiver) => { | ||
if (key === '__proto__') return klass.prototype; | ||
if (key === '__defineGetter__') return fakeDefineGetter(receiver); | ||
if (key === '__defineSetter__') return fakeDefineSetter(receiver); | ||
@@ -83,3 +104,3 @@ try { | ||
}, | ||
getPrototypeOf: (target) => { | ||
getPrototypeOf: (target) => { | ||
return klass.prototype; | ||
@@ -89,3 +110,3 @@ } | ||
}, | ||
function: function(fnc, traps, deepTraps, flags, mock) { | ||
function: (fnc, traps, deepTraps, flags, mock) => { | ||
const self = Decontextify.object(fnc, host.Object.assign({ | ||
@@ -115,2 +136,4 @@ apply: (target, context, args) => { | ||
if (key === '__proto__') return host.Function.prototype; | ||
if (key === '__defineGetter__') return fakeDefineGetter(receiver); | ||
if (key === '__defineSetter__') return fakeDefineSetter(receiver); | ||
@@ -123,3 +146,3 @@ try { | ||
}, | ||
getPrototypeOf: (target) => { | ||
getPrototypeOf: (target) => { | ||
return host.Function.prototype; | ||
@@ -131,3 +154,3 @@ } | ||
}, | ||
object: function(object, traps, deepTraps, flags, mock) { | ||
object: (object, traps, deepTraps, flags, mock) => { | ||
const proxy = new host.Proxy(object, host.Object.assign({ | ||
@@ -140,2 +163,4 @@ get: (target, key, receiver) => { | ||
if (key === '__proto__') return host.Object.prototype; | ||
if (key === '__defineGetter__') return fakeDefineGetter(receiver); | ||
if (key === '__defineSetter__') return fakeDefineSetter(receiver); | ||
@@ -157,4 +182,6 @@ try { | ||
getOwnPropertyDescriptor: (target, prop) => { | ||
let def; | ||
try { | ||
var def = host.Object.getOwnPropertyDescriptor(object, prop); | ||
def = host.Object.getOwnPropertyDescriptor(object, prop); | ||
} catch (e) { | ||
@@ -165,3 +192,4 @@ throw Decontextify.value(e); | ||
// Following code prevents V8 to throw | ||
// TypeError: 'getOwnPropertyDescriptor' on proxy: trap reported non-configurability for property '<prop>' which is either non-existant or configurable in the proxy target | ||
// TypeError: 'getOwnPropertyDescriptor' on proxy: trap reported non-configurability for property '<prop>' | ||
// which is either non-existant or configurable in the proxy target | ||
@@ -176,3 +204,3 @@ if (!def) { | ||
configurable: def.configurable === true | ||
} | ||
}; | ||
} else { | ||
@@ -184,6 +212,6 @@ return { | ||
configurable: def.configurable === true | ||
} | ||
}; | ||
} | ||
}, | ||
defineProperty: (target, key, descriptor) => { | ||
defineProperty: (target, key, descriptor) => { | ||
try { | ||
@@ -196,3 +224,3 @@ if (descriptor.get || descriptor.set) { | ||
configurable: descriptor.configurable === true | ||
}) | ||
}); | ||
} else { | ||
@@ -204,3 +232,3 @@ return host.Object.defineProperty(target, key, { | ||
configurable: descriptor.configurable === true | ||
}) | ||
}); | ||
} | ||
@@ -211,6 +239,6 @@ } catch (e) { | ||
}, | ||
getPrototypeOf: (target) => { | ||
getPrototypeOf: (target) => { | ||
return host.Object.prototype; | ||
}, | ||
setPrototypeOf: (target) => { | ||
setPrototypeOf: (target) => { | ||
throw new host.Error(OPNA); | ||
@@ -224,7 +252,7 @@ } | ||
}, | ||
value: function(value, traps, deepTraps, flags, mock) { | ||
value: (value, traps, deepTraps, flags, mock) => { | ||
if (Contextified.has(value)) { | ||
// Contextified object has returned back from vm | ||
return Contextified.get(value); | ||
} else if (Decontextify.proxies.has(value)) { | ||
} else if (Decontextify.proxies.has(value)) { | ||
// Decontextified proxy already exists, reuse | ||
@@ -234,2 +262,10 @@ return Decontextify.proxies.get(value); | ||
try { | ||
// If for some reason we get already decontextified value, get out. | ||
// Decontextifying already decontextified value breaks the security. | ||
if (value instanceof host.Object) return value; | ||
} catch (e) { | ||
throw new VMError('Failed to decontextify object.'); | ||
} | ||
switch (typeof value) { | ||
@@ -273,3 +309,3 @@ case 'object': | ||
} | ||
} | ||
}; | ||
@@ -283,3 +319,3 @@ /** | ||
arguments: function(args) { | ||
arguments: args => { | ||
if (!host.Array.isArray(args)) return new Array(); | ||
@@ -291,3 +327,3 @@ | ||
}, | ||
instance: function(instance, klass, deepTraps, flags) { | ||
instance: (instance, klass, deepTraps, flags) => { | ||
return Contextify.object(instance, { | ||
@@ -299,2 +335,4 @@ get: (target, key, receiver) => { | ||
if (key === '__proto__') return klass.prototype; | ||
if (key === '__defineGetter__') return fakeDefineGetter(receiver, true); | ||
if (key === '__defineSetter__') return fakeDefineSetter(receiver, true); | ||
@@ -307,3 +345,3 @@ try { | ||
}, | ||
getPrototypeOf: (target) => { | ||
getPrototypeOf: (target) => { | ||
return klass.prototype; | ||
@@ -313,3 +351,3 @@ } | ||
}, | ||
function: function(fnc, traps, deepTraps, flags, mock) { | ||
function: (fnc, traps, deepTraps, flags, mock) => { | ||
const self = Contextify.object(fnc, host.Object.assign({ | ||
@@ -328,3 +366,3 @@ apply: (target, context, args) => { | ||
// Fixes buffer unsafe allocation for node v6/7 | ||
if (host.version < 8 && fnc === host.Buffer && 'number' === typeof args[0]) { | ||
if (host.version < 8 && fnc === host.Buffer && 'number' === typeof args[0]) { | ||
args[0] = new Array(args[0]).fill(0); | ||
@@ -345,2 +383,4 @@ } | ||
if (key === '__proto__') return Function.prototype; | ||
if (key === '__defineGetter__') return fakeDefineGetter(receiver, true); | ||
if (key === '__defineSetter__') return fakeDefineSetter(receiver, true); | ||
@@ -353,3 +393,3 @@ try { | ||
}, | ||
getPrototypeOf: (target) => { | ||
getPrototypeOf: (target) => { | ||
return Function.prototype; | ||
@@ -361,3 +401,3 @@ } | ||
}, | ||
object: function(object, traps, deepTraps, flags, mock) { | ||
object: (object, traps, deepTraps, flags, mock) => { | ||
const proxy = new host.Proxy(object, host.Object.assign({ | ||
@@ -370,2 +410,4 @@ get: (target, key, receiver) => { | ||
if (key === '__proto__') return Object.prototype; | ||
if (key === '__defineGetter__') return fakeDefineGetter(receiver, true); | ||
if (key === '__defineSetter__') return fakeDefineSetter(receiver, true); | ||
@@ -389,4 +431,6 @@ try { | ||
getOwnPropertyDescriptor: (target, prop) => { | ||
let def; | ||
try { | ||
var def = host.Object.getOwnPropertyDescriptor(object, prop); | ||
def = host.Object.getOwnPropertyDescriptor(object, prop); | ||
} catch (e) { | ||
@@ -397,3 +441,4 @@ throw Contextify.value(e); | ||
// Following code prevents V8 to throw | ||
// TypeError: 'getOwnPropertyDescriptor' on proxy: trap reported non-configurability for property '<prop>' which is either non-existant or configurable in the proxy target | ||
// TypeError: 'getOwnPropertyDescriptor' on proxy: trap reported non-configurability for property '<prop>' | ||
// which is either non-existant or configurable in the proxy target | ||
@@ -408,3 +453,3 @@ if (!def) { | ||
configurable: def.configurable === true | ||
} | ||
}; | ||
} else { | ||
@@ -416,6 +461,6 @@ return { | ||
configurable: def.configurable === true | ||
} | ||
}; | ||
} | ||
}, | ||
defineProperty: (target, key, descriptor) => { | ||
defineProperty: (target, key, descriptor) => { | ||
if (flags && flags.protected && typeof descriptor.value === 'function') return false; | ||
@@ -430,3 +475,3 @@ | ||
configurable: descriptor.configurable === true | ||
}) | ||
}); | ||
} else { | ||
@@ -438,3 +483,3 @@ return host.Object.defineProperty(target, key, { | ||
configurable: descriptor.configurable === true | ||
}) | ||
}); | ||
} | ||
@@ -445,6 +490,6 @@ } catch (e) { | ||
}, | ||
getPrototypeOf: (target) => { | ||
getPrototypeOf: (target) => { | ||
return Object.prototype; | ||
}, | ||
setPrototypeOf: (target) => { | ||
setPrototypeOf: (target) => { | ||
throw new VMError(OPNA); | ||
@@ -458,7 +503,7 @@ } | ||
}, | ||
value: function(value, traps, deepTraps, flags, mock) { | ||
value: (value, traps, deepTraps, flags, mock) => { | ||
if (Decontextified.has(value)) { | ||
// Decontextified object has returned back to vm | ||
return Decontextified.get(value); | ||
} else if (Contextify.proxies.has(value)) { | ||
} else if (Contextify.proxies.has(value)) { | ||
// Contextified proxy already exists, reuse | ||
@@ -468,2 +513,10 @@ return Contextify.proxies.get(value); | ||
try { | ||
// If for some reason we get already contextified value, get out. | ||
// Contextifying already contextified value breaks the security. | ||
if (value instanceof local.Object) return value; | ||
} catch (e) { | ||
throw new VMError('Failed to contextify object.'); | ||
} | ||
switch (typeof value) { | ||
@@ -508,16 +561,20 @@ case 'object': | ||
}, | ||
globalValue: function(value, name) { | ||
return global[name] = Contextify.value(value); | ||
globalValue: (value, name) => { | ||
return (global[name] = Contextify.value(value)); | ||
}, | ||
readonly: function(value, mock) { | ||
readonly: (value, mock) => { | ||
return Contextify.value(value, null, FROZEN_TRAPS, null, mock); | ||
}, | ||
protected: function(value, mock) { | ||
protected: (value, mock) => { | ||
return Contextify.value(value, null, null, {protected: true}, mock); | ||
} | ||
} | ||
}; | ||
const LocalBuffer = global.Buffer = Contextify.readonly(host.Buffer, { | ||
allocUnsafe: function(size) { return this.alloc(size) }, | ||
allocUnsafeSlow: function(size) { return this.alloc(size) } | ||
allocUnsafe: function allocUnsafe(size) { | ||
return this.alloc(size); | ||
}, | ||
allocUnsafeSlow: function allocUnsafeSlow(size) { | ||
return this.alloc(size); | ||
} | ||
}); | ||
@@ -529,2 +586,2 @@ | ||
Buffer: LocalBuffer | ||
} | ||
}; |
@@ -0,1 +1,5 @@ | ||
/* eslint-disable global-require, no-use-before-define */ | ||
'use strict'; | ||
const fs = require('fs'); | ||
@@ -9,4 +13,2 @@ const vm = require('vm'); | ||
const PROTECTED = ['constructor', '__proto__']; | ||
const _compileToJS = function compileToJS(code, compiler, filename) { | ||
@@ -62,3 +64,3 @@ if ('function' === typeof compiler) return compiler(code, filename); | ||
*/ | ||
wrap(prefix, suffix) { | ||
@@ -76,11 +78,11 @@ if (this._wrapped) return this; | ||
*/ | ||
compile() { | ||
if (this._compiled) return this; | ||
this._compiled = new vm.Script(this.code, { | ||
filename: this.filename, | ||
displayErrors: false | ||
}) | ||
}); | ||
return this; | ||
@@ -153,7 +155,9 @@ } | ||
if ('object' !== typeof this.options.sandbox) { | ||
throw new VMError("Sandbox must be object."); | ||
throw new VMError('Sandbox must be object.'); | ||
} | ||
for (let name in this.options.sandbox) { | ||
this._internal.Contextify.globalValue(this.options.sandbox[name], name); | ||
for (const name in this.options.sandbox) { | ||
if (Object.prototype.hasOwnProperty.call(this.options.sandbox, name)) { | ||
this._internal.Contextify.globalValue(this.options.sandbox[name], name); | ||
} | ||
} | ||
@@ -204,3 +208,3 @@ } | ||
} | ||
const script = code instanceof VMScript ? code : new VMScript(code); | ||
@@ -250,3 +254,3 @@ | ||
wrapper: options.wrapper || 'commonjs', | ||
sourceExtensions: options.sourceExtensions || ['js'] | ||
sourceExtensions: options.sourceExtensions || ['js'] | ||
}; | ||
@@ -287,3 +291,3 @@ | ||
Promise | ||
} | ||
}; | ||
@@ -302,3 +306,3 @@ if (this.options.nesting) { | ||
}).call(this._context, require, host) | ||
}) | ||
}); | ||
@@ -308,7 +312,7 @@ const closure = vm.runInContext(`(function (vm, host, Contextify, Decontextify, Buffer) { ${sb} \n})`, this._context, { | ||
displayErrors: false | ||
}) | ||
}); | ||
Object.defineProperty(this, '_prepareRequire', { | ||
value: closure.call(this._context, this, host, this._internal.Contextify, this._internal.Decontextify, this._internal.Buffer) | ||
}) | ||
}); | ||
@@ -318,7 +322,9 @@ // prepare global sandbox | ||
if ('object' !== typeof this.options.sandbox) { | ||
throw new VMError("Sandbox must be object."); | ||
throw new VMError('Sandbox must be object.'); | ||
} | ||
for (let name in this.options.sandbox) { | ||
this._internal.Contextify.globalValue(this.options.sandbox[name], name); | ||
for (const name in this.options.sandbox) { | ||
if (Object.prototype.hasOwnProperty.call(this.options.sandbox, name)) { | ||
this._internal.Contextify.globalValue(this.options.sandbox[name], name); | ||
} | ||
} | ||
@@ -347,3 +353,3 @@ } | ||
} else { | ||
throw new VMError("Unrecognized method type."); | ||
throw new VMError('Unrecognized method type.'); | ||
} | ||
@@ -396,3 +402,4 @@ } | ||
* | ||
* First time you run this method, code is executed same way like in node's regular `require` - it's executed with `module`, `require`, `exports`, `__dirname`, `__filename` variables and expect result in `module.exports'. | ||
* First time you run this method, code is executed same way like in node's regular `require` - it's executed with | ||
* `module`, `require`, `exports`, `__dirname`, `__filename` variables and expect result in `module.exports'. | ||
* | ||
@@ -409,15 +416,17 @@ * @param {String} code Code to run. | ||
let dirname; | ||
let returned; | ||
if (filename) { | ||
filename = pa.resolve(filename); | ||
var dirname = pa.dirname(filename); | ||
dirname = pa.dirname(filename); | ||
} else { | ||
filename = null; | ||
var dirname = null; | ||
dirname = null; | ||
} | ||
const module = vm.runInContext("({exports: {}})", this._context, { | ||
const module = vm.runInContext('({exports: {}})', this._context, { | ||
displayErrors: false | ||
}); | ||
const script = code instanceof VMScript ? code : new VMScript(code, filename); | ||
@@ -432,3 +441,3 @@ script.wrap('(function (exports, require, module, __filename, __dirname) { ', ' \n})'); | ||
var returned = closure.call(this._context, module.exports, this._prepareRequire(dirname), module, filename, dirname); | ||
returned = closure.call(this._context, module.exports, this._prepareRequire(dirname), module, filename, dirname); | ||
} catch (e) { | ||
@@ -462,3 +471,3 @@ throw this._internal.Decontextify.value(e); | ||
} else { | ||
throw new VMError("Invalid arguments."); | ||
throw new VMError('Invalid arguments.'); | ||
} | ||
@@ -468,3 +477,3 @@ } | ||
if (arguments.length > 3) { | ||
throw new VMError("Invalid number of arguments."); | ||
throw new VMError('Invalid number of arguments.'); | ||
} | ||
@@ -491,3 +500,3 @@ | ||
if (fs.statSync(filename).isDirectory()) { | ||
throw new VMError("Script must be file, got directory."); | ||
throw new VMError('Script must be file, got directory.'); | ||
} | ||
@@ -494,0 +503,0 @@ |
@@ -0,8 +1,12 @@ | ||
/* eslint-disable no-shadow, no-invalid-this */ | ||
/* global vm, host, Contextify, Decontextify, VMError */ | ||
'use strict'; | ||
const {Script} = host.require('vm'); | ||
const fs = host.require('fs'); | ||
const pa = host.require('path'); | ||
const console = host.console; | ||
const BUILTIN_MODULES = host.process.binding('natives'); | ||
const JSON_PARSE = JSON.parse; | ||
const parseJSON = JSON.parse; | ||
@@ -22,12 +26,11 @@ /** | ||
const EXTENSIONS = { | ||
[".json"](module, filename) { | ||
['.json'](module, filename) { | ||
try { | ||
var code = fs.readFileSync(filename, "utf8"); | ||
const code = fs.readFileSync(filename, 'utf8'); | ||
module.exports = parseJSON(code); | ||
} catch (e) { | ||
throw Contextify.value(e); | ||
} | ||
module.exports = JSON_PARSE(code); | ||
}, | ||
[".node"](module, filename) { | ||
['.node'](module, filename) { | ||
if (vm.options.require.context === 'sandbox') throw new VMError('Native modules can be required only with context set to \'host\'.'); | ||
@@ -42,8 +45,7 @@ | ||
}; | ||
for (var i = 0; i < vm.options.sourceExtensions.length; i++) { | ||
var ext = vm.options.sourceExtensions[i]; | ||
EXTENSIONS["." + ext] = (module, filename, dirname) => { | ||
for (let i = 0; i < vm.options.sourceExtensions.length; i++) { | ||
const ext = vm.options.sourceExtensions[i]; | ||
EXTENSIONS['.' + ext] = (module, filename, dirname) => { | ||
if (vm.options.require.context !== 'sandbox') { | ||
@@ -56,19 +58,21 @@ try { | ||
} else { | ||
let closure; | ||
try { | ||
// Load module | ||
var contents = fs.readFileSync(filename, "utf8") | ||
if (typeof vm.options.compiler === "function") { | ||
contents = vm.options.compiler(contents, filename) | ||
let contents = fs.readFileSync(filename, 'utf8'); | ||
if (typeof vm.options.compiler === 'function') { | ||
contents = vm.options.compiler(contents, filename); | ||
} | ||
var code = `(function (exports, require, module, __filename, __dirname) { 'use strict'; ${contents} \n});`; | ||
const code = `(function (exports, require, module, __filename, __dirname) { 'use strict'; ${contents} \n});`; | ||
// Precompile script | ||
const script = new Script(code, { | ||
filename: filename || "vm.js", | ||
filename: filename || 'vm.js', | ||
displayErrors: false | ||
}); | ||
var closure = script.runInContext(global, { | ||
filename: filename || "vm.js", | ||
closure = script.runInContext(global, { | ||
filename: filename || 'vm.js', | ||
displayErrors: false | ||
@@ -80,6 +84,6 @@ }); | ||
// run script | ||
// run the script | ||
closure(module.exports, module.require, module, filename, dirname); | ||
} | ||
} | ||
}; | ||
} | ||
@@ -91,3 +95,3 @@ | ||
const _resolveFilename = function(path) { | ||
const _resolveFilename = (path) => { | ||
path = pa.resolve(path); | ||
@@ -102,4 +106,4 @@ | ||
// load as file | ||
for (var i = 0; i < vm.options.sourceExtensions.length; i++) { | ||
var ext = vm.options.sourceExtensions[i]; | ||
for (let i = 0; i < vm.options.sourceExtensions.length; i++) { | ||
const ext = vm.options.sourceExtensions[i]; | ||
if (fs.existsSync(`${path}.${ext}`)) return `${path}.${ext}`; | ||
@@ -113,7 +117,9 @@ } | ||
if (fs.existsSync(`${path}/package.json`)) { | ||
let pkg; | ||
try { | ||
var pkg = JSON.parse(fs.readFileSync(`${path}/package.json`, "utf8")); | ||
if (pkg.main == null) pkg.main = "index.js"; | ||
pkg = JSON.parse(fs.readFileSync(`${path}/package.json`, 'utf8')); | ||
if (pkg.main == null) pkg.main = 'index.js'; | ||
} catch (ex) { | ||
throw new VMError(`Module '${modulename}' has invalid package.json`, "EMODULEINVALID"); | ||
throw new VMError(`Module '${path}' has invalid package.json`, 'EMODULEINVALID'); | ||
} | ||
@@ -124,4 +130,4 @@ | ||
for (var i = 0; i < vm.options.sourceExtensions.length; i++) { | ||
var ext = vm.options.sourceExtensions[i]; | ||
for (let i = 0; i < vm.options.sourceExtensions.length; i++) { | ||
const ext = vm.options.sourceExtensions[i]; | ||
if (fs.existsSync(`${path}/index.${ext}`)) return `${path}/index.${ext}`; | ||
@@ -139,10 +145,10 @@ } | ||
const _requireBuiltin = function(modulename) { | ||
if (modulename === 'buffer') return ({Buffer}); | ||
if (BUILTINS[modulename]) return BUILTINS[modulename].exports; // Only compiled builtins are stored here | ||
const _requireBuiltin = (moduleName) => { | ||
if (moduleName === 'buffer') return ({Buffer}); | ||
if (BUILTINS[moduleName]) return BUILTINS[moduleName].exports; // Only compiled builtins are stored here | ||
if (modulename === 'util') { | ||
return Contextify.readonly(host.require(modulename), { | ||
if (moduleName === 'util') { | ||
return Contextify.readonly(host.require(moduleName), { | ||
// Allows VM context to use util.inherits | ||
inherits: function(ctor, superCtor) { | ||
inherits: (ctor, superCtor) => { | ||
ctor.super_ = superCtor; | ||
@@ -154,10 +160,10 @@ Object.setPrototypeOf(ctor.prototype, superCtor.prototype); | ||
if (modulename === 'events') { | ||
if (moduleName === 'events') { | ||
try { | ||
const script = new Script(`(function (exports, require, module, process) { 'use strict'; ${BUILTIN_MODULES[modulename]} \n});`, { | ||
filename: `${modulename}.vm.js` | ||
const script = new Script(`(function (exports, require, module, process) { 'use strict'; ${BUILTIN_MODULES[moduleName]} \n});`, { | ||
filename: `${moduleName}.vm.js` | ||
}); | ||
// setup module scope | ||
const module = BUILTINS[modulename] = { | ||
const module = BUILTINS[moduleName] = { | ||
exports: {}, | ||
@@ -176,3 +182,3 @@ require: _requireBuiltin | ||
return Contextify.readonly(host.require(modulename)); | ||
return Contextify.readonly(host.require(moduleName)); | ||
}; | ||
@@ -184,13 +190,15 @@ | ||
const _prepareRequire = function(current_dirname) { | ||
const _require = function(modulename) { | ||
if (vm.options.nesting && modulename === 'vm2') return {VM: Contextify.readonly(host.VM), NodeVM: Contextify.readonly(host.NodeVM)}; | ||
if (!vm.options.require) throw new VMError(`Access denied to require '${modulename}'`, "EDENIED"); | ||
if (modulename == null) throw new VMError("Module '' not found.", "ENOTFOUND"); | ||
if (typeof modulename !== 'string') throw new VMError(`Invalid module name '${modulename}'`, "EINVALIDNAME"); | ||
const _prepareRequire = currentDirname => { | ||
const _require = moduleName => { | ||
if (vm.options.nesting && moduleName === 'vm2') return {VM: Contextify.readonly(host.VM), NodeVM: Contextify.readonly(host.NodeVM)}; | ||
if (!vm.options.require) throw new VMError(`Access denied to require '${moduleName}'`, 'EDENIED'); | ||
if (moduleName == null) throw new VMError("Module '' not found.", 'ENOTFOUND'); | ||
if (typeof moduleName !== 'string') throw new VMError(`Invalid module name '${moduleName}'`, 'EINVALIDNAME'); | ||
let filename; | ||
// Mock? | ||
if (vm.options.require.mock && vm.options.require.mock[modulename]) { | ||
return Contextify.readonly(vm.options.require.mock[modulename]); | ||
if (vm.options.require.mock && vm.options.require.mock[moduleName]) { | ||
return Contextify.readonly(vm.options.require.mock[moduleName]); | ||
} | ||
@@ -200,20 +208,20 @@ | ||
if (BUILTIN_MODULES[modulename]) { | ||
if (BUILTIN_MODULES[moduleName]) { | ||
if (host.Array.isArray(vm.options.require.builtin)) { | ||
if (vm.options.require.builtin.indexOf('*') >= 0) { | ||
if (vm.options.require.builtin.indexOf(`-${modulename}`) >= 0) { | ||
throw new VMError(`Access denied to require '${modulename}'`, "EDENIED"); | ||
if (vm.options.require.builtin.indexOf(`-${moduleName}`) >= 0) { | ||
throw new VMError(`Access denied to require '${moduleName}'`, 'EDENIED'); | ||
} | ||
} else if (vm.options.require.builtin.indexOf(modulename) === -1) { | ||
throw new VMError(`Access denied to require '${modulename}'`, "EDENIED"); | ||
} else if (vm.options.require.builtin.indexOf(moduleName) === -1) { | ||
throw new VMError(`Access denied to require '${moduleName}'`, 'EDENIED'); | ||
} | ||
} else if (vm.options.require.builtin) { | ||
if (!vm.options.require.builtin[modulename]) { | ||
throw new VMError(`Access denied to require '${modulename}'`, "EDENIED"); | ||
if (!vm.options.require.builtin[moduleName]) { | ||
throw new VMError(`Access denied to require '${moduleName}'`, 'EDENIED'); | ||
} | ||
} else { | ||
throw new VMError(`Access denied to require '${modulename}'`, "EDENIED"); | ||
throw new VMError(`Access denied to require '${moduleName}'`, 'EDENIED'); | ||
} | ||
return _requireBuiltin(modulename); | ||
return _requireBuiltin(moduleName); | ||
} | ||
@@ -223,32 +231,32 @@ | ||
if (!vm.options.require.external) throw new VMError(`Access denied to require '${modulename}'`, "EDENIED"); | ||
if (!vm.options.require.external) throw new VMError(`Access denied to require '${moduleName}'`, 'EDENIED'); | ||
if (/^(\.|\.\/|\.\.\/)/.exec(modulename)) { | ||
if (/^(\.|\.\/|\.\.\/)/.exec(moduleName)) { | ||
// Module is relative file, e.g. ./script.js or ../script.js | ||
if (!current_dirname) throw new VMError("You must specify script path to load relative modules.", "ENOPATH"); | ||
if (!currentDirname) throw new VMError('You must specify script path to load relative modules.', 'ENOPATH'); | ||
var filename = _resolveFilename(`${current_dirname}/${modulename}`); | ||
} else if (/^(\/|\\|[a-zA-Z]:\\)/.exec(modulename)) { | ||
filename = _resolveFilename(`${currentDirname}/${moduleName}`); | ||
} else if (/^(\/|\\|[a-zA-Z]:\\)/.exec(moduleName)) { | ||
// Module is absolute file, e.g. /script.js or //server/script.js or C:\script.js | ||
var filename = _resolveFilename(modulename); | ||
filename = _resolveFilename(moduleName); | ||
} else { | ||
// Check node_modules in path | ||
if (!current_dirname) throw new VMError("You must specify script path to load relative modules.", "ENOPATH"); | ||
if (!currentDirname) throw new VMError('You must specify script path to load relative modules.', 'ENOPATH'); | ||
if(Array.isArray(vm.options.require.external)) { | ||
const isWhitelisted = vm.options.require.external.indexOf(modulename) !== -1 | ||
if (!isWhitelisted) throw new VMError(`The module '${modulename}' is not whitelisted in VM.`, "EDENIED"); | ||
if (Array.isArray(vm.options.require.external)) { | ||
const isWhitelisted = vm.options.require.external.indexOf(moduleName) !== -1; | ||
if (!isWhitelisted) throw new VMError(`The module '${moduleName}' is not whitelisted in VM.`, 'EDENIED'); | ||
} | ||
const paths = current_dirname.split(pa.sep); | ||
const paths = currentDirname.split(pa.sep); | ||
while (paths.length) { | ||
let path = paths.join(pa.sep); | ||
const path = paths.join(pa.sep); | ||
//console.log modulename, "#{path}#{pa.sep}node_modules#{pa.sep}#{modulename}" | ||
// console.log moduleName, "#{path}#{pa.sep}node_modules#{pa.sep}#{moduleName}" | ||
var filename = _resolveFilename(`${path}${pa.sep}node_modules${pa.sep}${modulename}`); | ||
filename = _resolveFilename(`${path}${pa.sep}node_modules${pa.sep}${moduleName}`); | ||
if (filename) break; | ||
@@ -260,3 +268,3 @@ | ||
if (!filename) throw new VMError(`Cannot find module '${modulename}'`, "ENOTFOUND"); | ||
if (!filename) throw new VMError(`Cannot find module '${moduleName}'`, 'ENOTFOUND'); | ||
@@ -272,3 +280,3 @@ // return cache whenever possible | ||
if (dirname.indexOf(requiredPath) !== 0) { | ||
throw new VMError(`Module '${modulename}' is not allowed to be required. The path is outside the border!`, "EDENIED"); | ||
throw new VMError(`Module '${moduleName}' is not allowed to be required. The path is outside the border!`, 'EDENIED'); | ||
} | ||
@@ -289,3 +297,3 @@ } | ||
throw new VMError(`Failed to load '${modulename}': Unknown type.`, "ELOADFAIL"); | ||
throw new VMError(`Failed to load '${moduleName}': Unknown type.`, 'ELOADFAIL'); | ||
}; | ||
@@ -300,10 +308,10 @@ | ||
global.setTimeout = function(callback, delay, ...args) { | ||
const tmr = host.setTimeout(Decontextify.value(function() { | ||
callback.apply(null, args) | ||
global.setTimeout = (callback, delay, ...args) => { | ||
const tmr = host.setTimeout(Decontextify.value(() => { | ||
callback(...args); | ||
}), Decontextify.value(delay)); | ||
const local = { | ||
ref() { return tmr.ref(); }, | ||
unref() { return tmr.unref(); } | ||
ref: () => tmr.ref(), | ||
unref: () => tmr.unref() | ||
}; | ||
@@ -315,10 +323,10 @@ | ||
global.setInterval = function(callback, interval, ...args) { | ||
const tmr = host.setInterval(Decontextify.value(function() { | ||
callback.apply(null, args) | ||
global.setInterval = (callback, interval, ...args) => { | ||
const tmr = host.setInterval(Decontextify.value(() => { | ||
callback(...args); | ||
}), Decontextify.value(interval)); | ||
const local = { | ||
ref() { return tmr.ref(); }, | ||
unref() { return tmr.unref(); } | ||
ref: () => tmr.ref(), | ||
unref: () => tmr.unref() | ||
}; | ||
@@ -330,10 +338,10 @@ | ||
global.setImmediate = function(callback, ...args) { | ||
const tmr = host.setImmediate(Decontextify.value(function() { | ||
callback.apply(null, args) | ||
global.setImmediate = (callback, ...args) => { | ||
const tmr = host.setImmediate(Decontextify.value(() => { | ||
callback(...args); | ||
})); | ||
const local = { | ||
ref() { return tmr.ref(); }, | ||
unref() { return tmr.unref(); } | ||
ref: () => tmr.ref(), | ||
unref: () => tmr.unref() | ||
}; | ||
@@ -345,3 +353,3 @@ | ||
global.clearTimeout = function(local) { | ||
global.clearTimeout = (local) => { | ||
host.clearTimeout(TIMERS.get(local)); | ||
@@ -351,3 +359,3 @@ return null; | ||
global.clearInterval = function(local) { | ||
global.clearInterval = (local) => { | ||
host.clearInterval(TIMERS.get(local)); | ||
@@ -357,3 +365,3 @@ return null; | ||
global.clearImmediate = function(local) { | ||
global.clearImmediate = (local) => { | ||
host.clearImmediate(TIMERS.get(local)); | ||
@@ -374,13 +382,13 @@ return null; | ||
nextTick(callback, ...args) { | ||
if (typeof callback !== 'function') { | ||
throw new Error('Callback must be a function.'); | ||
}; | ||
if (typeof callback !== 'function') { | ||
throw new Error('Callback must be a function.'); | ||
} | ||
try { | ||
return host.process.nextTick(Decontextify.value(function() { | ||
callback.apply(null, args) | ||
})); | ||
} catch (e) { | ||
throw Contextify.value(e); | ||
} | ||
try { | ||
return host.process.nextTick(Decontextify.value(() => { | ||
callback(...args); | ||
})); | ||
} catch (e) { | ||
throw Contextify.value(e); | ||
} | ||
}, | ||
@@ -440,3 +448,3 @@ hrtime() { | ||
} | ||
return this; | ||
@@ -447,3 +455,3 @@ }, | ||
if (arguments.length) { | ||
throw new Error("Access denied to set umask."); | ||
throw new Error('Access denied to set umask.'); | ||
} | ||
@@ -450,0 +458,0 @@ |
@@ -16,3 +16,3 @@ { | ||
], | ||
"version": "3.6.5", | ||
"version": "3.6.6", | ||
"main": "index.js", | ||
@@ -23,3 +23,5 @@ "repository": "github:patriksimek/vm2", | ||
"devDependencies": { | ||
"mocha": "^2.0.0" | ||
"eslint": "^5.11.1", | ||
"eslint-config-integromat": "^1.5.0", | ||
"mocha": "^5.2.0" | ||
}, | ||
@@ -30,3 +32,4 @@ "engines": { | ||
"scripts": { | ||
"test": "mocha test" | ||
"test": "mocha test", | ||
"pretest": "eslint ." | ||
}, | ||
@@ -33,0 +36,0 @@ "bin": { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
65281
12
1484
4
3