Comparing version 3.2.0 to 3.3.0
@@ -0,1 +1,5 @@ | ||
v3.2.0 (2017-02-10) | ||
------------------- | ||
[new] Added support for pre-compiled scripts (VMScript) | ||
v3.1.0 (2016-09-03) | ||
@@ -2,0 +6,0 @@ ------------------- |
@@ -7,6 +7,6 @@ const fs = require('fs'); | ||
if (process.argv[2]) { | ||
let path = pa.resolve(process.argv[2]); | ||
const path = pa.resolve(process.argv[2]); | ||
console.log(`\x1B[90m[vm] creating VM for ${path}\x1B[39m`); | ||
let started = Date.now(); | ||
const started = Date.now(); | ||
@@ -26,3 +26,3 @@ try { | ||
} else { | ||
let {stack} = ex; | ||
const {stack} = ex; | ||
@@ -29,0 +29,0 @@ if (stack) { |
@@ -49,3 +49,3 @@ 'use strict' | ||
let arr = new host.Array(); | ||
const arr = new host.Array(); | ||
for (let i = 0, l = args.length; i < l; i++) arr[i] = Decontextify.value(args[i]); | ||
@@ -74,3 +74,3 @@ return arr; | ||
function: function(fnc, traps, deepTraps, mock) { | ||
let self = Decontextify.object(fnc, host.Object.assign({ | ||
const self = Decontextify.object(fnc, host.Object.assign({ | ||
apply: (target, context, args) => { | ||
@@ -114,3 +114,3 @@ try { | ||
object: function(object, traps, deepTraps, mock) { | ||
let proxy = new host.Proxy(object, host.Object.assign({ | ||
const proxy = new host.Proxy(object, host.Object.assign({ | ||
get: (target, key, receiver) => { | ||
@@ -253,3 +253,3 @@ if (key === 'vmProxyTarget' && DEBUG) return object; | ||
let arr = new Array(); | ||
const arr = new Array(); | ||
for (let i = 0, l = args.length; i < l; i++) arr[i] = Contextify.value(args[i]); | ||
@@ -278,3 +278,3 @@ return arr; | ||
function: function(fnc, traps, deepTraps, mock) { | ||
let self = Contextify.object(fnc, host.Object.assign({ | ||
const self = Contextify.object(fnc, host.Object.assign({ | ||
apply: (target, context, args) => { | ||
@@ -318,3 +318,3 @@ try { | ||
object: function(object, traps, deepTraps, mock) { | ||
let proxy = new host.Proxy(object, host.Object.assign({ | ||
const proxy = new host.Proxy(object, host.Object.assign({ | ||
get: (target, key, receiver) => { | ||
@@ -321,0 +321,0 @@ if (key === 'vmProxyTarget' && DEBUG) return object; |
@@ -9,3 +9,3 @@ const fs = require('fs'); | ||
const _compileToJS = function(code, compiler) { | ||
const _compileToJS = function compileToJS(code, compiler) { | ||
if ('function' === typeof compiler) return compiler(code); | ||
@@ -31,7 +31,32 @@ | ||
const _freeze = function freeze(object) { | ||
if (typeof object === 'object' || object === 'function') { | ||
object = new Proxy(object, { | ||
set: (target, key) => { throw new Error('Object is read-only.') }, | ||
setPrototypeOf: (target, key) => { throw new Error('Object is read-only.') }, | ||
defineProperty: (target, key) => { throw new Error('Object is read-only.') }, | ||
deleteProperty: (target, key) => { throw new Error('Object is read-only.') }, | ||
isExtensible: (target, key) => false, | ||
preventExtensions: (target) => { throw new Error('Object is read-only.') } | ||
}); | ||
} | ||
return object; | ||
} | ||
/** | ||
* Class Script | ||
* | ||
* @class | ||
*/ | ||
class VMScript { | ||
/** | ||
* Create VMScript instance. | ||
* | ||
* @param {String} code Code to run. | ||
* @param {String} [filename] Filename that shows up in any stack traces produced from this script. | ||
* @return {VMScript} | ||
*/ | ||
constructor(code, filename) { | ||
@@ -41,2 +66,8 @@ this.code = code; | ||
} | ||
/** | ||
* Wraps the code. | ||
* | ||
* @return {VMScript} | ||
*/ | ||
@@ -49,2 +80,8 @@ wrap(prefix, postfix) { | ||
} | ||
/** | ||
* Compiles the code. If called multiple times, the code is only compiled once. | ||
* | ||
* @return {VMScript} | ||
*/ | ||
@@ -71,2 +108,14 @@ compile() { | ||
/** | ||
* Makes the value read only. | ||
* | ||
* @static | ||
* @param {*} value Value to freeze. | ||
* @return {*} Frozen value. | ||
*/ | ||
static freeze(object) { | ||
return _freeze(object); | ||
} | ||
/** | ||
* Create VM instance. | ||
@@ -88,3 +137,3 @@ * | ||
let host = { | ||
const host = { | ||
console, | ||
@@ -148,3 +197,3 @@ String, | ||
let script = code instanceof VMScript ? code : new VMScript(code); | ||
const script = code instanceof VMScript ? code : new VMScript(code); | ||
@@ -165,3 +214,5 @@ try { | ||
* Class NodeVM. | ||
* | ||
* | ||
* @class | ||
* @extends {EventEmitter} | ||
* @property {Object} module Pointer to main module. | ||
@@ -172,2 +223,14 @@ */ | ||
/** | ||
* Makes the value read only. | ||
* | ||
* @static | ||
* @param {*} value Value to freeze. | ||
* @return {*} Frozen value. | ||
*/ | ||
static freeze(object) { | ||
return _freeze(object); | ||
} | ||
/** | ||
* Create NodeVM instance. | ||
@@ -195,3 +258,3 @@ * | ||
let host = { | ||
const host = { | ||
require, | ||
@@ -244,3 +307,3 @@ process, | ||
let closure = vm.runInContext(`(function (vm, host, Contextify, Decontextify, Buffer) { ${sb} \n})`, this._context, { | ||
const closure = vm.runInContext(`(function (vm, host, Contextify, Decontextify, Buffer) { ${sb} \n})`, this._context, { | ||
filename: `${__dirname}/sandbox.js`, | ||
@@ -292,2 +355,3 @@ displayErrors: false | ||
* | ||
* @param {String} module Module name. | ||
* @return {*} Exported module. | ||
@@ -324,11 +388,11 @@ */ | ||
let module = vm.runInContext("({exports: {}})", this._context, { | ||
const module = vm.runInContext("({exports: {}})", this._context, { | ||
displayErrors: false | ||
}); | ||
let script = code instanceof VMScript ? code : new VMScript(code, filename); | ||
const script = code instanceof VMScript ? code : new VMScript(code, filename); | ||
script.wrap('(function (exports, require, module, __filename, __dirname) { ', ' \n})'); | ||
try { | ||
let closure = script.compile()._compiled.runInContext(this._context, { | ||
const closure = script.compile()._compiled.runInContext(this._context, { | ||
filename: script.filename, | ||
@@ -404,4 +468,2 @@ displayErrors: false | ||
* | ||
* @param {String} message Error message. | ||
* | ||
* @class | ||
@@ -414,2 +476,9 @@ * @extends {Error} | ||
class VMError extends Error { | ||
/** | ||
* Create VMError instance. | ||
* | ||
* @param {String} message Error message. | ||
* @return {VMError} | ||
*/ | ||
constructor(message) { | ||
@@ -416,0 +485,0 @@ super(message); |
@@ -53,3 +53,3 @@ const {Script} = host.require('vm'); | ||
// Precompile script | ||
let script = new Script(code, { | ||
const script = new Script(code, { | ||
filename: filename || "vm.js", | ||
@@ -80,4 +80,4 @@ displayErrors: false | ||
let exists = fs.existsSync(path); | ||
let isdir = exists ? fs.statSync(path).isDirectory() : false; | ||
const exists = fs.existsSync(path); | ||
const isdir = exists ? fs.statSync(path).isDirectory() : false; | ||
@@ -132,3 +132,3 @@ // direct file match | ||
try { | ||
let script = new Script(`(function (exports, require, module, process) { 'use strict'; ${BUILTIN_MODULES[modulename]} \n});`, { | ||
const script = new Script(`(function (exports, require, module, process) { 'use strict'; ${BUILTIN_MODULES[modulename]} \n});`, { | ||
filename: `${modulename}.vm.js` | ||
@@ -138,3 +138,3 @@ }); | ||
// setup module scope | ||
let module = BUILTINS[modulename] = { | ||
const module = BUILTINS[modulename] = { | ||
exports: {}, | ||
@@ -214,3 +214,3 @@ require: _requireBuiltin | ||
let paths = current_dirname.split(pa.sep); | ||
const paths = current_dirname.split(pa.sep); | ||
@@ -234,7 +234,7 @@ while (paths.length) { | ||
let dirname = pa.dirname(filename); | ||
let extname = pa.extname(filename); | ||
const dirname = pa.dirname(filename); | ||
const extname = pa.extname(filename); | ||
if (vm.options.require.root) { | ||
let requiredPath = pa.resolve(vm.options.require.root); | ||
const requiredPath = pa.resolve(vm.options.require.root); | ||
if (dirname.indexOf(requiredPath) !== 0) { | ||
@@ -245,3 +245,3 @@ throw new VMError(`Module '${modulename}' is not allowed to be required. The path is outside the border!`, "EDENIED"); | ||
let module = CACHE[filename] = { | ||
const module = CACHE[filename] = { | ||
filename, | ||
@@ -270,7 +270,7 @@ exports: {}, | ||
global.setTimeout = function(callback, delay, ...args) { | ||
let tmr = host.setTimeout(function() { | ||
const tmr = host.setTimeout(function() { | ||
callback.apply(null, args) | ||
}, delay); | ||
let local = { | ||
const local = { | ||
ref() { return tmr.ref(); }, | ||
@@ -285,7 +285,7 @@ unref() { return tmr.unref(); } | ||
global.setInterval = function(callback, interval, ...args) { | ||
let tmr = host.setInterval(function() { | ||
const tmr = host.setInterval(function() { | ||
callback.apply(null, args) | ||
}, interval); | ||
let local = { | ||
const local = { | ||
ref() { return tmr.ref(); }, | ||
@@ -300,7 +300,7 @@ unref() { return tmr.unref(); } | ||
global.setImmediate = function(callback, ...args) { | ||
let tmr = host.setImmediate(function() { | ||
const tmr = host.setImmediate(function() { | ||
callback.apply(null, args) | ||
}); | ||
let local = { | ||
const local = { | ||
ref() { return tmr.ref(); }, | ||
@@ -307,0 +307,0 @@ unref() { return tmr.unref(); } |
@@ -16,3 +16,3 @@ { | ||
], | ||
"version": "3.2.0", | ||
"version": "3.3.0", | ||
"main": "index.js", | ||
@@ -19,0 +19,0 @@ "repository": { |
@@ -23,2 +23,17 @@ # vm2 [![NPM Version][npm-image]][npm-url] [![NPM Downloads][downloads-image]][downloads-url] [![Package Quality][quality-image]][quality-url] [![Travis CI][travis-image]][travis-url] | ||
**What is the difference between Node's vm and vm2?** | ||
Try it yourself: | ||
```javascript | ||
const vm = require('vm'); | ||
vm.runInNewContext('this.constructor.constructor("return process")().exit()'); | ||
console.log('Never gets executed.'); | ||
``` | ||
```javascript | ||
const {VM} = require('vm2'); | ||
new VM().run('this.constructor.constructor("return process")().exit()'); | ||
``` | ||
## Installation | ||
@@ -63,2 +78,4 @@ | ||
* [VMScript](#vmscript) | ||
* [Error handling](#error-handling) | ||
* [Read-only objects](#read-only-objects) | ||
* [Cross-sandbox relationships](#cross-sandbox-relationships) | ||
@@ -219,2 +236,31 @@ * [CLI](#cli) | ||
## Read-only objects | ||
To prevent sandboxed script to add/change/delete properties to/from the proxied objects, you can use `VM.freeze`/`NodeVM.freeze` methods to make the object read-only. Rather than freezing the object itself (like builtin `Object.freeze` method does) it creates a new proxy so the original object remains untouched. | ||
**Example without using `VM.freeze`:** | ||
```javascript | ||
const util = { | ||
add: (a, b) => a + b | ||
} | ||
const vm = new VM({ | ||
sandbox: {util} | ||
}); | ||
vm.run('util.add = (a, b) => a - b'); | ||
console.log(util.add(1, 1)); // returns 0 | ||
``` | ||
**Example with using `VM.freeze`:** | ||
```javascript | ||
const vm = new VM({ | ||
sandbox: {util: VM.freeze(util)} | ||
}); | ||
vm.run('util.add = (a, b) => a - b'); // throws Object is read-only. | ||
``` | ||
## Cross-sandbox relationships | ||
@@ -226,3 +272,3 @@ | ||
let sandbox = { | ||
const sandbox = { | ||
object: new Object(), | ||
@@ -233,3 +279,3 @@ func: new Function(), | ||
let vm = new VM({sandbox}); | ||
const vm = new VM({sandbox}); | ||
@@ -236,0 +282,0 @@ assert.ok(vm.run(`object`) === sandbox.object); |
@@ -739,1 +739,51 @@ const assert = require("assert"); | ||
}) | ||
describe('read-only contextified items', () => { | ||
it('without read-only', done => { | ||
let x = { | ||
a() { | ||
return 'a'; | ||
}, | ||
b() { | ||
return 'b' | ||
} | ||
} | ||
let vm = new VM({ | ||
sandbox: {x} | ||
}); | ||
vm.run('x.a = () => { return `-` }; (y) => { y.b = () => { return `--` } }')(x); | ||
assert.strictEqual(x.a(), '-'); | ||
assert.strictEqual(x.b(), '--'); | ||
done() | ||
}) | ||
it('with read-only', done => { | ||
let x = VM.freeze({ | ||
a() { | ||
return 'a'; | ||
}, | ||
b() { | ||
return 'b' | ||
} | ||
}); | ||
let vm = new VM({ | ||
sandbox: {x} | ||
}); | ||
assert.throws(() => { | ||
vm.run('x.a = () => { return `-` };'); | ||
}, /Object is read-only\./); | ||
assert.throws(() => { | ||
vm.run('(y) => { y.b = () => { return `--` } }')(x); | ||
}, /Object is read-only\./); | ||
done() | ||
}) | ||
}) |
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
72484
15
1841
339