Comparing version 3.0.1 to 3.1.0
@@ -8,6 +8,6 @@ const fs = require('fs'); | ||
let path = pa.resolve(process.argv[2]); | ||
console.log(`\x1B[90m[vm] creating VM for ${path}\x1B[39m`); | ||
let started = Date.now(); | ||
try { | ||
@@ -20,3 +20,3 @@ NodeVM.file(path, { | ||
}); | ||
console.log(`\x1B[90m[vm] VM completed in ${Date.now() - started}ms\x1B[39m`); | ||
@@ -28,3 +28,3 @@ } catch (ex) { | ||
let {stack} = ex; | ||
if (stack) { | ||
@@ -31,0 +31,0 @@ console.error(`\x1B[31m[vm:error] ${stack}\x1B[39m`); |
@@ -31,6 +31,6 @@ 'use strict' | ||
super(message); | ||
this.name = 'VMError'; | ||
this.code = code; | ||
ERROR_CST(this, this.constructor); | ||
@@ -46,6 +46,6 @@ } | ||
proxies: new host.WeakMap(), | ||
arguments: function(args) { | ||
if (!host.Array.isArray(args)) return new host.Array(); | ||
let arr = new host.Array(); | ||
@@ -62,3 +62,3 @@ for (let i = 0, l = args.length; i < l; i++) arr[i] = Decontextify.value(args[i]); | ||
if (key === '__proto__') return klass.prototype; | ||
try { | ||
@@ -80,3 +80,3 @@ return Decontextify.value(instance[key]); | ||
context = Contextify.value(context); | ||
// Set context of all arguments to vm's context. | ||
@@ -101,3 +101,3 @@ return Decontextify.value(fnc.apply(context, Contextify.arguments(args))); | ||
if (key === '__proto__') return host.Function.prototype; | ||
try { | ||
@@ -113,3 +113,3 @@ return Decontextify.value(fnc[key], deepTraps); | ||
}, traps), deepTraps); | ||
return self; | ||
@@ -125,3 +125,3 @@ }, | ||
if (key === '__proto__') return host.Object.prototype; | ||
try { | ||
@@ -147,6 +147,6 @@ return Decontextify.value(object[key], deepTraps); | ||
} | ||
// 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 | ||
if (!def) { | ||
@@ -198,3 +198,3 @@ return undefined; | ||
}, traps)); | ||
Decontextify.proxies.set(object, proxy); | ||
@@ -212,3 +212,3 @@ Decontextified.set(proxy, object); | ||
} | ||
switch (typeof value) { | ||
@@ -240,6 +240,6 @@ case 'object': | ||
return Decontextify.function(value, traps, deepTraps, mock); | ||
case 'undefined': | ||
return undefined; | ||
default: // string, number, boolean, symbol | ||
@@ -257,6 +257,6 @@ return value; | ||
proxies: new host.WeakMap(), | ||
arguments: function(args) { | ||
if (!host.Array.isArray(args)) return new Array(); | ||
let arr = new Array(); | ||
@@ -321,3 +321,3 @@ for (let i = 0, l = args.length; i < l; i++) arr[i] = Contextify.value(args[i]); | ||
}, traps), deepTraps); | ||
return self; | ||
@@ -354,3 +354,3 @@ }, | ||
} | ||
// Following code prevents V8 to throw | ||
@@ -418,3 +418,3 @@ // TypeError: 'getOwnPropertyDescriptor' on proxy: trap reported non-configurability for property '<prop>' which is either non-existant or configurable in the proxy target | ||
} | ||
switch (typeof value) { | ||
@@ -447,6 +447,6 @@ case 'object': | ||
return Contextify.function(value, traps, deepTraps, mock); | ||
case 'undefined': | ||
return undefined; | ||
default: // string, number, boolean, symbol | ||
@@ -453,0 +453,0 @@ return value; |
103
lib/main.js
@@ -18,3 +18,3 @@ const fs = require('fs'); | ||
return require('coffee-script').compile(code, {header: false, bare: true}); | ||
case 'javascript': | ||
@@ -25,3 +25,3 @@ case 'java-script': | ||
return code; | ||
default: | ||
@@ -34,3 +34,3 @@ throw new VMError(`Unsupported compiler '${compiler}'.`); | ||
* Class VM. | ||
* | ||
* | ||
* @property {Object} options VM options. | ||
@@ -42,10 +42,10 @@ */ | ||
* Create VM instance. | ||
* | ||
* | ||
* @param {Object} [options] VM options. | ||
* @return {VM} | ||
*/ | ||
constructor(options = {}) { | ||
super(); | ||
// defaults | ||
@@ -92,3 +92,3 @@ this.options = { | ||
}); | ||
// prepare global sandbox | ||
@@ -99,3 +99,3 @@ if (this.options.sandbox) { | ||
} | ||
for (let name in this.options.sandbox) { | ||
@@ -106,10 +106,10 @@ this._internal.Contextify.globalValue(this.options.sandbox[name], name); | ||
} | ||
/** | ||
* Run the code in VM. | ||
* | ||
* | ||
* @param {String} code Code to run. | ||
* @return {*} Result of executed code. | ||
*/ | ||
run(code) { | ||
@@ -124,3 +124,3 @@ if (this.options.compiler !== 'javascript') { | ||
}); | ||
try { | ||
@@ -137,6 +137,6 @@ return this._internal.Decontextify.value(script.runInContext(this._context, { | ||
} | ||
/** | ||
* Class NodeVM. | ||
* | ||
* | ||
* @property {Object} module Pointer to main module. | ||
@@ -148,12 +148,12 @@ */ | ||
* Create NodeVM instance. | ||
* | ||
* | ||
* Unlike VM, NodeVM lets you use require same way like in regular node. | ||
* | ||
* | ||
* @param {Object} [options] VM options. | ||
* @return {NodeVM} | ||
*/ | ||
constructor(options = {}) { | ||
super(); | ||
// defaults | ||
@@ -166,3 +166,4 @@ this.options = { | ||
require: options.require != null ? options.require : false, | ||
nesting: options.nesting != null ? options.nesting : false | ||
nesting: options.nesting != null ? options.nesting : false, | ||
wrapper: options.wrapper != null ? options.wrapper : 'commonjs' | ||
}; | ||
@@ -217,3 +218,3 @@ | ||
}) | ||
let closure = vm.runInContext(`(function (vm, host, Contextify, Decontextify, Buffer) { ${sb} \n})`, this._context, { | ||
@@ -233,3 +234,3 @@ filename: `${__dirname}/sandbox.js`, | ||
} | ||
for (let name in this.options.sandbox) { | ||
@@ -239,3 +240,3 @@ this._internal.Contextify.globalValue(this.options.sandbox[name], name); | ||
} | ||
if (this.options.require && this.options.require.import) { | ||
@@ -245,3 +246,3 @@ if (!Array.isArray(this.options.require.import)) { | ||
} | ||
for (let i = 0, l = this.options.require.import.length; i < l; i++) { | ||
@@ -252,7 +253,7 @@ this.require(this.options.require.import[i]); | ||
} | ||
/** | ||
* @deprecated | ||
*/ | ||
call(method, ...args) { | ||
@@ -266,3 +267,3 @@ if ('function' === typeof method) { | ||
} | ||
/** | ||
@@ -273,12 +274,12 @@ * Require a module in VM and return it's exports. | ||
*/ | ||
require(module) { | ||
return this.run(`module.exports = require('${module}');`, 'vm.js'); | ||
} | ||
/** | ||
* Run the code in NodeVM. | ||
* | ||
* Run the code in NodeVM. | ||
* | ||
* 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'. | ||
* | ||
* | ||
* @param {String} code Code to run. | ||
@@ -288,3 +289,3 @@ * @param {String} [filename] Filename that shows up in any stack traces produced from this script. | ||
*/ | ||
run(code, filename) { | ||
@@ -298,3 +299,3 @@ if (this.options.compiler !== 'javascript') { | ||
var dirname = pa.dirname(filename); | ||
} else { | ||
@@ -308,3 +309,3 @@ filename = null; | ||
}); | ||
let script = new vm.Script(`(function (exports, require, module, __filename, __dirname) { ${code} \n})`, { | ||
@@ -314,3 +315,3 @@ filename: filename || "vm.js", | ||
}); | ||
try { | ||
@@ -321,4 +322,4 @@ let closure = script.runInContext(this._context, { | ||
}); | ||
closure.call(this._context, module.exports, this._prepareRequire(dirname), module, filename, dirname); | ||
var returned = closure.call(this._context, module.exports, this._prepareRequire(dirname), module, filename, dirname); | ||
} catch (e) { | ||
@@ -328,3 +329,7 @@ throw this._internal.Decontextify.value(e); | ||
return this._internal.Decontextify.value(module.exports); | ||
if (this.options.wrapper === 'commonjs') { | ||
return this._internal.Decontextify.value(module.exports); | ||
} else { | ||
return this._internal.Decontextify.value(returned); | ||
} | ||
} | ||
@@ -334,3 +339,3 @@ | ||
* Create NodeVM and run code inside it. | ||
* | ||
* | ||
* @param {String} script Javascript code. | ||
@@ -341,3 +346,3 @@ * @param {String} [filename] File name (used in stack traces only). | ||
*/ | ||
static code(script, filename, options) { | ||
@@ -354,3 +359,3 @@ if (filename != null) { | ||
} | ||
if (arguments.length > 3) { | ||
@@ -362,6 +367,6 @@ throw new VMError("Invalid number of arguments."); | ||
} | ||
/** | ||
* Create NodeVM and run script from file inside it. | ||
* | ||
* | ||
* @param {String} [filename] File name (used in stack traces only). | ||
@@ -371,10 +376,10 @@ * @param {Object} [options] VM options. | ||
*/ | ||
static file(filename, options) { | ||
filename = pa.resolve(filename); | ||
if (!fs.existsSync(filename)) { | ||
throw new VMError(`Script '${filename}' not found.`); | ||
} | ||
if (fs.statSync(filename).isDirectory()) { | ||
@@ -390,5 +395,5 @@ throw new VMError("Script must be file, got directory."); | ||
* VMError. | ||
* | ||
* | ||
* @param {String} message Error message. | ||
* | ||
* | ||
* @class | ||
@@ -403,3 +408,3 @@ * @extends {Error} | ||
super(message); | ||
this.name = 'VMError'; | ||
@@ -406,0 +411,0 @@ |
@@ -15,3 +15,3 @@ const {Script} = host.require('vm'); | ||
'use strict'; | ||
const global = this; | ||
@@ -29,3 +29,3 @@ | ||
} | ||
module.exports = JSON_PARSE(code); | ||
@@ -35,3 +35,3 @@ }, | ||
if (vm.options.require.context === 'sandbox') throw new VMError('Native modules can be required only with context set to \'host\'.'); | ||
try { | ||
@@ -54,5 +54,5 @@ module.exports = Contextify.readonly(host.require(filename)); | ||
var code = `(function (exports, require, module, __filename, __dirname) { 'use strict'; ${fs.readFileSync(filename, "utf8")} \n});`; | ||
// Precompile script | ||
let script = new Script(code, { | ||
let script = new Script(code, { | ||
filename: filename || "vm.js", | ||
@@ -62,3 +62,3 @@ displayErrors: false | ||
var closure = script.runInContext(global, { | ||
var closure = script.runInContext(global, { | ||
filename: filename || "vm.js", | ||
@@ -68,5 +68,5 @@ displayErrors: false | ||
} catch (ex) { | ||
throw Contextify.value(e); | ||
throw Contextify.value(ex); | ||
} | ||
// run script | ||
@@ -77,3 +77,3 @@ closure(module.exports, module.require, module, filename, dirname); | ||
}; | ||
/** | ||
@@ -85,6 +85,6 @@ * Resolve filename. | ||
path = pa.resolve(path); | ||
let exists = fs.existsSync(path); | ||
let isdir = exists ? fs.statSync(path).isDirectory() : false; | ||
// direct file match | ||
@@ -94,9 +94,9 @@ if (exists && !isdir) return path; | ||
// load as file | ||
if (fs.existsSync(`${path}.js`)) return `${path}.js`; | ||
if (fs.existsSync(`${path}.node`)) return `${path}.node`; | ||
if (fs.existsSync(`${path}.json`)) return `${path}.json`; | ||
// load as directory | ||
if (fs.existsSync(`${path}/package.json`)) { | ||
@@ -109,20 +109,20 @@ try { | ||
} | ||
return _resolveFilename(`${path}/${pkg.main}`); | ||
} | ||
if (fs.existsSync(`${path}/index.js`)) return `${path}/index.js`; | ||
if (fs.existsSync(`${path}/index.node`)) return `${path}/index.node`; | ||
return null; | ||
}; | ||
/** | ||
* Builtin require. | ||
*/ | ||
const _requireBuiltin = function(modulename) { | ||
if (modulename === 'buffer') return ({Buffer}); | ||
if (BUILTINS[modulename]) return BUILTINS[modulename].exports; // Only compiled builtins are stored here | ||
if (modulename === 'util') { | ||
@@ -137,3 +137,3 @@ return Contextify.readonly(host.require(modulename), { | ||
} | ||
if (modulename === 'events') { | ||
@@ -144,3 +144,3 @@ try { | ||
}); | ||
// setup module scope | ||
@@ -151,6 +151,6 @@ let module = BUILTINS[modulename] = { | ||
}; | ||
// run script | ||
script.runInContext(global)(module.exports, module.require, module, host.process); | ||
return module.exports; | ||
@@ -161,10 +161,10 @@ } catch (e) { | ||
} | ||
return Contextify.readonly(host.require(modulename)); | ||
}; | ||
/** | ||
* Prepare require. | ||
*/ | ||
const _prepareRequire = function(current_dirname) { | ||
@@ -176,11 +176,11 @@ const _require = function(modulename) { | ||
if (typeof modulename !== 'string') throw new VMError(`Invalid module name '${modulename}'`, "EINVALIDNAME"); | ||
// Mock? | ||
if (vm.options.require.mock && vm.options.require.mock[modulename]) { | ||
return Contextify.readonly(vm.options.require.mock[modulename]); | ||
} | ||
// Builtin? | ||
if (BUILTIN_MODULES[modulename]) { | ||
@@ -202,8 +202,8 @@ if (host.Array.isArray(vm.options.require.builtin)) { | ||
} | ||
return _requireBuiltin(modulename); | ||
} | ||
// External? | ||
if (!vm.options.require.external) throw new VMError(`Access denied to require '${modulename}'`, "EDENIED"); | ||
@@ -213,3 +213,3 @@ | ||
// 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"); | ||
@@ -220,25 +220,25 @@ | ||
// Module is absolute file, e.g. /script.js or //server/script.js or C:\script.js | ||
var 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"); | ||
let paths = current_dirname.split(pa.sep); | ||
while (paths.length) { | ||
let path = paths.join(pa.sep); | ||
//console.log modulename, "#{path}#{pa.sep}node_modules#{pa.sep}#{modulename}" | ||
var filename = _resolveFilename(`${path}${pa.sep}node_modules${pa.sep}${modulename}`); | ||
if (filename) break; | ||
paths.pop(); | ||
} | ||
} | ||
if (!filename) throw new VMError(`Cannot find module '${modulename}'`, "ENOTFOUND"); | ||
// return cache whenever possible | ||
@@ -249,3 +249,3 @@ if (CACHE[filename]) return CACHE[filename].exports; | ||
let extname = pa.extname(filename); | ||
if (vm.options.require.root) { | ||
@@ -257,3 +257,3 @@ let requiredPath = pa.resolve(vm.options.require.root); | ||
} | ||
let module = CACHE[filename] = { | ||
@@ -264,5 +264,5 @@ filename, | ||
}; | ||
// lookup extensions | ||
if (EXTENSIONS[extname]) { | ||
@@ -272,6 +272,6 @@ EXTENSIONS[extname](module, filename, dirname); | ||
} | ||
throw new VMError(`Failed to load '${modulename}': Unknown type.`, "ELOADFAIL"); | ||
}; | ||
return _require; | ||
@@ -283,3 +283,3 @@ }; | ||
*/ | ||
global.setTimeout = function(callback, delay, ...args) { | ||
@@ -289,3 +289,3 @@ let tmr = host.setTimeout(function() { | ||
}, delay); | ||
let local = { | ||
@@ -295,7 +295,7 @@ ref() { return tmr.ref(); }, | ||
}; | ||
TIMERS.set(local, tmr); | ||
return local; | ||
}; | ||
global.setInterval = function(callback, interval, ...args) { | ||
@@ -305,3 +305,3 @@ let tmr = host.setInterval(function() { | ||
}, interval); | ||
let local = { | ||
@@ -311,7 +311,7 @@ ref() { return tmr.ref(); }, | ||
}; | ||
TIMERS.set(local, tmr); | ||
return local; | ||
}; | ||
global.setImmediate = function(callback, ...args) { | ||
@@ -321,3 +321,3 @@ let tmr = host.setImmediate(function() { | ||
}); | ||
let local = { | ||
@@ -327,7 +327,7 @@ ref() { return tmr.ref(); }, | ||
}; | ||
TIMERS.set(local, tmr); | ||
return local; | ||
}; | ||
global.clearTimeout = function(local) { | ||
@@ -337,3 +337,3 @@ host.clearTimeout(TIMERS.get(local)); | ||
}; | ||
global.clearInterval = function(local) { | ||
@@ -343,3 +343,3 @@ host.clearInterval(TIMERS.get(local)); | ||
}; | ||
global.clearImmediate = function(local) { | ||
@@ -349,3 +349,3 @@ host.clearImmediate(TIMERS.get(local)); | ||
}; | ||
global.process = { | ||
@@ -368,7 +368,7 @@ argv: [], | ||
} | ||
host.process.on(name, Decontextify.value(handler)); | ||
return this; | ||
}, | ||
once(name, handler) { | ||
@@ -382,7 +382,7 @@ if (name !== 'beforeExit' && name !== 'exit') { | ||
}, | ||
listeners(name) { | ||
return Contextify.readonly(host.process.listeners(name)); | ||
}, | ||
removeListener(name, handler) { | ||
@@ -392,3 +392,3 @@ host.process.removeListener(name, Decontextify.value(handler)); | ||
}, | ||
umask() { | ||
@@ -398,7 +398,7 @@ if (arguments.length) { | ||
} | ||
return host.process.umask(); | ||
} | ||
}; | ||
if (vm.options.console === 'inherit') { | ||
@@ -411,3 +411,3 @@ global.console = Contextify.readonly(host.console); | ||
return null; | ||
}, | ||
}, | ||
info(...args) { | ||
@@ -414,0 +414,0 @@ vm.emit('console.info', ...Decontextify.arguments(args)); |
@@ -16,3 +16,3 @@ { | ||
], | ||
"version": "3.0.1", | ||
"version": "3.1.0", | ||
"main": "index.js", | ||
@@ -19,0 +19,0 @@ "repository": { |
@@ -73,3 +73,3 @@ # vm2 [![NPM Version][npm-image]][npm-url] [![Package Quality][quality-image]][quality-url] [![Travis CI][travis-image]][travis-url] | ||
* `timeout` - Script timeout in milliseconds. | ||
* `timeout` - Script timeout in milliseconds. | ||
* `sandbox` - VM's global object. | ||
@@ -116,2 +116,3 @@ * `compiler` - `javascript` (default) or `coffeescript` or custom compiler function. | ||
* `nesting` - `true` to enable VMs nesting (default: `false`). | ||
* `wrapper` - `commonjs` (default) to wrap script into CommonJS wrapper, `none` to retrieve value returned by the script. | ||
@@ -144,2 +145,8 @@ **IMPORTANT**: Timeout is not effective for NodeVM so it is not immune to `while (true) {}` or similar evil. | ||
When `wrapper` is set to `none`, `NodeVM` behaves more like `VM` for synchronous code. | ||
```javascript | ||
assert.ok(vm.run('return true') === true); | ||
``` | ||
**TIP**: See tests for more usage examples. | ||
@@ -146,0 +153,0 @@ |
@@ -1,1 +0,1 @@ | ||
{"working": true} | ||
{"working": true} |
@@ -8,3 +8,3 @@ const assert = require("assert"); | ||
let vm; | ||
class TestClass { | ||
@@ -50,3 +50,3 @@ constructor() { | ||
} | ||
before(done => { | ||
@@ -56,3 +56,3 @@ vm = new VM({sandbox}); | ||
}) | ||
it('common', done => { | ||
@@ -70,3 +70,3 @@ assert.ok(vm.run(`global.__proto__ === Object.prototype`)); | ||
assert.ok(vm.run(`Array.prototype.__proto__ === Object.prototype`)); | ||
assert.strictEqual(sandbox.test.object.y === sandbox.test.object.y.valueOf(), true); | ||
@@ -91,3 +91,3 @@ assert.strictEqual(vm.run("test.object.y instanceof Function"), true); | ||
assert.strictEqual(vm.run("test.object.valueOf().y.constructor('return (function(){return this})().isVM')()"), true); | ||
let o = vm.run("let x = {a: test.date, b: test.date};x"); | ||
@@ -100,3 +100,3 @@ assert.strictEqual(vm.run("x.valueOf().a instanceof Date"), true); | ||
assert.strictEqual(o.a === sandbox.test.date, true); | ||
o = vm.run("let y = new Date(); let z = {a: y, b: y};z"); | ||
@@ -108,6 +108,6 @@ assert.strictEqual(o.isVMProxy, true); | ||
assert.strictEqual(o.a === o.b, true); | ||
done(); | ||
}) | ||
it('class', done => { | ||
@@ -117,27 +117,27 @@ assert.strictEqual(vm.run("new test.klass()").isVMProxy, undefined); | ||
assert.strictEqual(vm.run("new test.klass()") instanceof TestClass, true); | ||
//vm.run("class LocalClass extends test.klass {}"); | ||
done(); | ||
}) | ||
it('string', done => { | ||
assert.strictEqual(vm.run("(test.string).constructor === String"), true); | ||
assert.strictEqual(vm.run("typeof(test.stringO) === 'string' && test.string.valueOf instanceof Object"), true); | ||
done(); | ||
}) | ||
it('number', done => { | ||
assert.strictEqual(vm.run("typeof(test.numberO) === 'number' && test.number.valueOf instanceof Object"), true); | ||
done(); | ||
}) | ||
it('boolean', done => { | ||
assert.strictEqual(vm.run("typeof(test.booleanO) === 'boolean' && test.boolean.valueOf instanceof Object"), true); | ||
done(); | ||
}) | ||
it('date', done => { | ||
@@ -147,12 +147,12 @@ assert.strictEqual(vm.run("test.date instanceof Date"), true); | ||
assert.strictEqual(vm.run("test.date"), sandbox.test.date); | ||
done(); | ||
}) | ||
it('regexp', done => { | ||
assert.strictEqual(vm.run("test.regexp instanceof RegExp"), true); | ||
done(); | ||
}) | ||
it('buffer', done => { | ||
@@ -164,3 +164,3 @@ assert.strictEqual(vm.run("test.buffer.inspect()"), '<Buffer 00 01>', '#1'); | ||
assert.strictEqual(vm.run("class Buffer2 extends Buffer {};new Buffer2(5)").fill(1).inspect(), '<Buffer 01 01 01 01 01>'); | ||
let {a, b, c, d} = vm.run(` | ||
@@ -184,6 +184,6 @@ let a = new Buffer([0x01, 0x02]); | ||
assert.ok(d.constructor.constructor === Function, '#12'); | ||
({a: a, b: b, c: c, d: d}) | ||
`); | ||
assert.ok(a instanceof Buffer); | ||
@@ -201,6 +201,6 @@ assert.ok(b instanceof Buffer); | ||
assert.ok(d.constructor.constructor === Function); | ||
done(); | ||
}) | ||
it('function', done => { | ||
@@ -210,6 +210,6 @@ assert.strictEqual(vm.run("test.function instanceof Function"), true, '#1'); | ||
assert.strictEqual(vm.run("test.function()() instanceof Object"), true, '#3'); | ||
done(); | ||
}) | ||
it('object', done => { | ||
@@ -223,18 +223,18 @@ assert.strictEqual(vm.run("test.object instanceof Object && test.object.x === 1"), true, '#1'); | ||
assert.strictEqual(vm.run("Object.getOwnPropertyDescriptor(test.object, 'y').hasOwnProperty.constructor('return (function(){return this})().isVM')()"), true, '#7'); | ||
done(); | ||
}) | ||
it('null', done => { | ||
assert.strictEqual(vm.run("test.nil === null"), true); | ||
done(); | ||
}) | ||
it('undefined', done => { | ||
assert.strictEqual(vm.run("test.undef === undefined"), true); | ||
done(); | ||
}) | ||
it('symbol', done => { | ||
@@ -248,6 +248,6 @@ assert.strictEqual(vm.run("Symbol.for('foo') === test.symbol2"), true); | ||
assert.strictEqual(vm.run("Symbol.keyFor(test.symbol2)"), 'foo'); | ||
done(); | ||
}) | ||
it('error', done => { | ||
@@ -261,3 +261,3 @@ assert.strictEqual(vm.run("Object.getOwnPropertyDescriptor(test.error, 'stack').get.constructor === Function;"), true); | ||
vm = null; | ||
done(); | ||
@@ -269,3 +269,3 @@ }) | ||
let vm; | ||
before(done => { | ||
@@ -276,3 +276,3 @@ let sandbox = { | ||
} | ||
Object.defineProperty(sandbox.sub, 'getter', { | ||
@@ -288,3 +288,3 @@ get() { | ||
}) | ||
vm = new VM({ | ||
@@ -294,12 +294,12 @@ timeout: 10, | ||
}) | ||
done(); | ||
}) | ||
it('globals', done => { | ||
assert.equal(vm.run("round(1.5)"), 2); | ||
done(); | ||
}) | ||
it('errors', done => { | ||
@@ -312,6 +312,6 @@ assert.throws(() => vm.run("notdefined"), /notdefined is not defined/); | ||
}) | ||
done(); | ||
}) | ||
it('timeout', done => { | ||
@@ -322,6 +322,6 @@ assert.throws(() => new VM({ | ||
assert.throws(() => vm.run("sub.getter"), /Script execution timed out\./); | ||
done(); | ||
}) | ||
it('timers', done => { | ||
@@ -331,11 +331,11 @@ assert.equal(vm.run("global.setTimeout"), void 0); | ||
assert.equal(vm.run("global.setImmediate"), void 0); | ||
done(); | ||
}) | ||
it('various attacks #1', done => { | ||
let vm2 = new VM({sandbox: {log: console.log, boom: function() { throw new Error(); }}}); | ||
assert.strictEqual(vm2.run("this.constructor.constructor('return Function(\\'return Function\\')')()() === this.constructor.constructor('return Function')()"), true); | ||
assert.throws(() => vm2.run(` | ||
@@ -360,3 +360,3 @@ const ForeignFunction = global.constructor.constructor; | ||
} | ||
Reflect.construct = exploit; | ||
@@ -371,3 +371,3 @@ new Buffer([0]); | ||
`), '#4'); | ||
assert.doesNotThrow(() => vm2.run(` | ||
@@ -378,3 +378,3 @@ global.String = function(text) { | ||
`)('asdf'), '#5'); | ||
assert.doesNotThrow(() => vm2.run(` | ||
@@ -385,3 +385,3 @@ global.String = function(text) { | ||
`)(new String('asdf')), '#6'); | ||
assert.doesNotThrow(() => vm2.run(` | ||
@@ -395,3 +395,3 @@ global.Buffer = function(value) { | ||
}) | ||
it('various attacks #2', done => { | ||
@@ -404,3 +404,3 @@ let vm2 = new VM({ | ||
}); | ||
assert.doesNotThrow(() => vm2.run(` | ||
@@ -412,3 +412,3 @@ Object.assign = function (o) { | ||
`), '#1'); | ||
assert.doesNotThrow(() => vm2.run(` | ||
@@ -421,3 +421,3 @@ try { | ||
`), '#2'); | ||
assert.doesNotThrow(() => vm2.run(` | ||
@@ -432,3 +432,3 @@ let o; | ||
`), '#3'); | ||
assert.doesNotThrow(() => vm2.run(` | ||
@@ -444,3 +444,3 @@ let method = () => {}; | ||
`)('asdf'), '#4'); | ||
assert.doesNotThrow(() => vm2.run(` | ||
@@ -454,3 +454,3 @@ let proxy2 = new Proxy(function() {}, { | ||
`)('asdf'), '#5'); | ||
assert.strictEqual(vm2.run(` | ||
@@ -460,11 +460,11 @@ global.DEBUG = true; | ||
`), undefined, '#6'); | ||
assert.throws(() => vm2.run(` | ||
global.constructor.constructor('return this')().constructor.constructor('return process')() | ||
`), /process is not defined/, '#7'); | ||
assert.throws(() => vm2.run(` | ||
global.__proto__.constructor.constructor('return this')().constructor.constructor('return process')() | ||
`), /process is not defined/, '#8'); | ||
assert.doesNotThrow(() => vm2.run(` | ||
@@ -480,3 +480,3 @@ if (!(Object.keys(boom) instanceof Array)) throw new Error('Shouldnt be there.'); | ||
vm = null; | ||
done(); | ||
@@ -488,9 +488,9 @@ }) | ||
let vm; | ||
before(done => { | ||
vm = new NodeVM; | ||
done(); | ||
}) | ||
it('globals', done => { | ||
@@ -500,31 +500,31 @@ let ex; | ||
assert.equal(ex.isVM, true); | ||
done(); | ||
}) | ||
it('errors', done => { | ||
assert.throws(() => vm.run("notdefined"), /notdefined is not defined/); | ||
done(); | ||
}) | ||
it('prevent global access', done => { | ||
assert.throws(() => vm.run("process.exit()"), /(undefined is not a function|process\.exit is not a function)/); | ||
done(); | ||
}) | ||
it('arguments attack', done => { | ||
assert.strictEqual(vm.run("module.exports = (function() { return arguments.callee.caller.constructor === Function; })()"), true); | ||
assert.throws(() => vm.run("module.exports = (function() { return arguments.callee.caller.caller.toString(); })()"), /Cannot read property 'toString' of null/); | ||
done(); | ||
}) | ||
it('global attack', done => { | ||
assert.equal(vm.run("module.exports = console.log.constructor('return (function(){return this})().isVM')()"), true); | ||
done(); | ||
}) | ||
it.skip('timeout (not supported by Node\'s VM)', done => { | ||
@@ -534,9 +534,9 @@ assert.throws(() => new NodeVM({ | ||
}).run("while (true) {}"), /Script execution timed out\./); | ||
done(); | ||
}) | ||
after(done => { | ||
vm = null; | ||
done(); | ||
@@ -553,8 +553,8 @@ }) | ||
}) | ||
assert.equal(vm.run(`module.exports = require('${__dirname}/data/json.json')`).working, true); | ||
done(); | ||
}) | ||
it.skip('run coffee-script', done => { | ||
@@ -567,16 +567,16 @@ let vm = new NodeVM({ | ||
}) | ||
assert.equal(vm.run("module.exports = working: true").working, true); | ||
done(); | ||
}) | ||
it('disabled require', done => { | ||
let vm = new NodeVM; | ||
assert.throws(() => vm.run("require('fs')"), /Access denied to require 'fs'/); | ||
done(); | ||
}) | ||
it('disable setters on builtin modules', done => { | ||
@@ -588,9 +588,9 @@ let vm = new NodeVM({ | ||
}) | ||
vm.run("require('fs').readFileSync = undefined"); | ||
assert.strictEqual(require('fs').readFileSync instanceof Function, true); | ||
vm.run("require('fs').readFileSync.thisPropertyShouldntBeThere = true"); | ||
assert.strictEqual(require('fs').readFileSync.thisPropertyShouldntBeThere, undefined); | ||
assert.throws(() => vm.run("Object.defineProperty(require('fs'), 'test', {})"), err => { | ||
@@ -602,3 +602,3 @@ assert.ok(err instanceof TypeError); | ||
}) | ||
assert.throws(() => vm.run("'use strict'; delete require('fs').readFileSync"), err => { | ||
@@ -610,6 +610,6 @@ assert.ok(err instanceof TypeError); | ||
}) | ||
done(); | ||
}) | ||
it('enabled require for certain modules', done => { | ||
@@ -621,8 +621,8 @@ let vm = new NodeVM({ | ||
}) | ||
assert.doesNotThrow(() => vm.run("require('fs')")); | ||
done(); | ||
}) | ||
it('require relative', done => { | ||
@@ -634,20 +634,20 @@ let vm = new NodeVM({ | ||
}) | ||
vm.run("require('foobar')", __filename); | ||
done(); | ||
}) | ||
it('arguments attack', done => { | ||
let vm = new NodeVM; | ||
assert.throws(() => vm.run("module.exports = function fce(msg) { return arguments.callee.caller.toString(); }")(), /Cannot read property 'toString' of null/); | ||
vm = new NodeVM; | ||
assert.throws(() => vm.run("module.exports = function fce(msg) { return fce.caller.toString(); }")(), /Cannot read property 'toString' of null/); | ||
done(); | ||
}) | ||
it('builtin module arguments attack', done => { | ||
@@ -663,6 +663,6 @@ let vm = new NodeVM({ | ||
}) | ||
vm.run("var fs = require('fs'); fs.exists(parentfilename, function() {try {arguments.callee.caller.toString()} catch (err) {return done();}; done(new Error('Missing expected exception'))})"); | ||
}) | ||
it('path attack', done => { | ||
@@ -675,8 +675,8 @@ let vm = new NodeVM({ | ||
}) | ||
assert.throws(() => vm.run("var test = require('../package.json')", __filename), /Module '\.\.\/package.json' is not allowed to be required\. The path is outside the border!/); | ||
done(); | ||
}) | ||
it('process events', done => { | ||
@@ -688,3 +688,3 @@ let vm = new NodeVM({ | ||
}) | ||
let sandbox = vm.run("global.VM2_HANDLER = function() { VM2_COUNTER++ }; process.on('exit', VM2_HANDLER); module.exports = global;"); | ||
@@ -697,6 +697,6 @@ process.emit('exit'); | ||
assert.strictEqual(sandbox.VM2_COUNTER, 1); | ||
done(); | ||
}) | ||
it('timers', done => { | ||
@@ -708,5 +708,5 @@ let vm = new NodeVM({ | ||
}) | ||
vm.run('let i = setImmediate(function() { global.TICK = true; });clearImmediate(i);'); | ||
setImmediate(() => { | ||
@@ -717,3 +717,3 @@ assert.strictEqual(vm.run('module.exports = global.TICK'), void 0); | ||
}) | ||
it('mock', done => { | ||
@@ -729,6 +729,6 @@ let vm = new NodeVM({ | ||
}) | ||
assert.strictEqual(vm.run("module.exports = require('fs').constructor.constructor === Function"), true); | ||
assert.strictEqual(vm.run("module.exports = require('fs').readFileSync()"), 'Nice try!'); | ||
done(); | ||
@@ -743,3 +743,3 @@ }) | ||
}) | ||
let nestedObject = vm.run(` | ||
@@ -751,7 +751,19 @@ const {VM} = require('vm2'); | ||
`, 'vm.js'); | ||
assert.strictEqual(nestedObject.constructor.constructor === Function, true); | ||
done(); | ||
}) | ||
}) | ||
describe('wrappers', () => { | ||
it('none', done => { | ||
let vm = new NodeVM({ | ||
wrapper: 'none' | ||
}) | ||
assert.strictEqual(vm.run('return 2 + 2'), 4) | ||
done() | ||
}) | ||
}) |
Sorry, the diff of this file is not supported yet
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
64939
13
1672
229