From 4c079a4a73087fc86c4d47f924d03cf7ca59ee5f Mon Sep 17 00:00:00 2001 From: Jacob Beard Date: Sun, 7 Aug 2016 15:29:59 -0400 Subject: [PATCH 1/8] Use persistent iframe to support closures. --- index.js | 47 ++++++++++------------------------------------- 1 file changed, 10 insertions(+), 37 deletions(-) diff --git a/index.js b/index.js index 644efd1..abf7975 100644 --- a/index.js +++ b/index.js @@ -35,12 +35,19 @@ var defineProp = (function() { }()); var globals = ['Array', 'Boolean', 'Date', 'Error', 'EvalError', 'Function', -'Infinity', 'JSON', 'Math', 'NaN', 'Number', 'Object', 'RangeError', +//'Infinity', +'JSON', 'Math', 'NaN', 'Number', 'Object', 'RangeError', 'ReferenceError', 'RegExp', 'String', 'SyntaxError', 'TypeError', 'URIError', 'decodeURI', 'decodeURIComponent', 'encodeURI', 'encodeURIComponent', 'escape', 'eval', 'isFinite', 'isNaN', 'parseFloat', 'parseInt', 'undefined', 'unescape']; -function Context() {} +function Context() { + this._iframe = document.createElement('iframe'); + if (!this._iframe.style) iframe.style = {}; + this._iframe.style.display = 'none'; + + document.body.appendChild(this._iframe); +} Context.prototype = {}; var Script = exports.Script = function NodeScript (code) { @@ -53,13 +60,7 @@ Script.prototype.runInContext = function (context) { throw new TypeError("needs a 'context' argument."); } - var iframe = document.createElement('iframe'); - if (!iframe.style) iframe.style = {}; - iframe.style.display = 'none'; - - document.body.appendChild(iframe); - - var win = iframe.contentWindow; + var win = context._iframe.contentWindow; var wEval = win.eval, wExecScript = win.execScript; if (!wEval && wExecScript) { @@ -68,36 +69,8 @@ Script.prototype.runInContext = function (context) { wEval = win.eval; } - forEach(Object_keys(context), function (key) { - win[key] = context[key]; - }); - forEach(globals, function (key) { - if (context[key]) { - win[key] = context[key]; - } - }); - - var winKeys = Object_keys(win); - var res = wEval.call(win, this.code); - forEach(Object_keys(win), function (key) { - // Avoid copying circular objects like `top` and `window` by only - // updating existing context properties or new properties in the `win` - // that was only introduced after the eval. - if (key in context || indexOf(winKeys, key) === -1) { - context[key] = win[key]; - } - }); - - forEach(globals, function (key) { - if (!(key in context)) { - defineProp(context, key, win[key]); - } - }); - - document.body.removeChild(iframe); - return res; }; From 8907981dc53b48c30d042a7b8679967c1820e7b9 Mon Sep 17 00:00:00 2001 From: Jacob Beard Date: Sun, 14 Aug 2016 19:46:43 -0400 Subject: [PATCH 2/8] Added method isContext. --- index.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index abf7975..dd46084 100644 --- a/index.js +++ b/index.js @@ -104,8 +104,12 @@ exports.createContext = Script.createContext = function (context) { var copy = new Context(); if(typeof context === 'object') { forEach(Object_keys(context), function (key) { - copy[key] = context[key]; + copy._iframe.contentWindow[key] = context[key]; }); } return copy; }; + +exports.isContext = function(sandbox){ + return sandbox instanceof Context; +}; From 8ac3680a4e9ee0780bcb75cf6e8cfc4f8d42d65d Mon Sep 17 00:00:00 2001 From: Jacob Beard Date: Tue, 16 Aug 2016 21:48:35 -0400 Subject: [PATCH 3/8] Added test for closure --- index.js | 42 ++++++++++++++++++++++++++++++++++++++---- test/vm.js | 16 ++++++++++++++++ 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index dd46084..0382d6a 100644 --- a/index.js +++ b/index.js @@ -42,11 +42,19 @@ var globals = ['Array', 'Boolean', 'Date', 'Error', 'EvalError', 'Function', 'eval', 'isFinite', 'isNaN', 'parseFloat', 'parseInt', 'undefined', 'unescape']; function Context() { - this._iframe = document.createElement('iframe'); - if (!this._iframe.style) iframe.style = {}; - this._iframe.style.display = 'none'; + + var iframe = document.createElement('iframe'); + if (!iframe.style) iframe.style = {}; + iframe.style.display = 'none'; - document.body.appendChild(this._iframe); + document.body.appendChild(iframe); + + Object.defineProperty(this, "_iframe", { + enumerable: false, + writable: true + }); + + this._iframe = iframe; } Context.prototype = {}; @@ -68,9 +76,34 @@ Script.prototype.runInContext = function (context) { wExecScript.call(win, 'null'); wEval = win.eval; } + + forEach(Object_keys(context), function (key) { + win[key] = context[key]; + }); + forEach(globals, function (key) { + if (context[key]) { + win[key] = context[key]; + } + }); + var winKeys = Object_keys(win); + var res = wEval.call(win, this.code); + forEach(Object_keys(win), function (key) { + // Avoid copying circular objects like `top` and `window` by only + // updating existing context properties or new properties in the `win` + // that was only introduced after the eval. + if (key in context || indexOf(winKeys, key) === -1) { + context[key] = win[key]; + } + }); + + forEach(globals, function (key) { + if (!(key in context)) { + defineProp(context, key, win[key]); + } + }); return res; }; @@ -104,6 +137,7 @@ exports.createContext = Script.createContext = function (context) { var copy = new Context(); if(typeof context === 'object') { forEach(Object_keys(context), function (key) { + copy[key] = context[key]; copy._iframe.contentWindow[key] = context[key]; }); } diff --git a/test/vm.js b/test/vm.js index ea8cd31..febd2ed 100644 --- a/test/vm.js +++ b/test/vm.js @@ -33,3 +33,19 @@ test('vmRunInContext', function (t) { vm.runInContext('var y = 1', context); t.deepEqual(context, { foo: 1, x: 1, y: 1 }); }); + + +test('vmRunInContext with closure', function (t) { + t.plan(4); + + var context = vm.createContext(); + + vm.runInContext('var x = 1', context); + t.deepEqual(context, { x: 1 }); + + vm.runInContext('function y() { return ++x; }', context); + var x = vm.runInContext('y()', context); + t.equal(x, 2); + t.equal(context.x, 2); + t.equal(typeof context.y, 'function'); +}); From 9edd35bd00aba2d3cf213b1f77c63aa2124d99bc Mon Sep 17 00:00:00 2001 From: Jacob Beard Date: Tue, 16 Aug 2016 21:56:34 -0400 Subject: [PATCH 4/8] Removed Infinity global, as this was causing an error in Chrome. --- index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/index.js b/index.js index 0382d6a..971c8b6 100644 --- a/index.js +++ b/index.js @@ -35,7 +35,6 @@ var defineProp = (function() { }()); var globals = ['Array', 'Boolean', 'Date', 'Error', 'EvalError', 'Function', -//'Infinity', 'JSON', 'Math', 'NaN', 'Number', 'Object', 'RangeError', 'ReferenceError', 'RegExp', 'String', 'SyntaxError', 'TypeError', 'URIError', 'decodeURI', 'decodeURIComponent', 'encodeURI', 'encodeURIComponent', 'escape', From 32797cb25727273ba3f5c39f4a4c3420b107b41c Mon Sep 17 00:00:00 2001 From: Jacob Beard Date: Tue, 16 Aug 2016 21:59:43 -0400 Subject: [PATCH 5/8] Added Infinity back in. --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 971c8b6..0be98c2 100644 --- a/index.js +++ b/index.js @@ -35,7 +35,7 @@ var defineProp = (function() { }()); var globals = ['Array', 'Boolean', 'Date', 'Error', 'EvalError', 'Function', -'JSON', 'Math', 'NaN', 'Number', 'Object', 'RangeError', +'Infinity', 'JSON', 'Math', 'NaN', 'Number', 'Object', 'RangeError', 'ReferenceError', 'RegExp', 'String', 'SyntaxError', 'TypeError', 'URIError', 'decodeURI', 'decodeURIComponent', 'encodeURI', 'encodeURIComponent', 'escape', 'eval', 'isFinite', 'isNaN', 'parseFloat', 'parseInt', 'undefined', 'unescape']; From e429aa275ec6744c90e5edc2d4bc3a5f102213d1 Mon Sep 17 00:00:00 2001 From: Jacob Beard Date: Tue, 16 Aug 2016 22:10:14 -0400 Subject: [PATCH 6/8] Added test for isContext. --- test/vm.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/vm.js b/test/vm.js index febd2ed..d50fa3c 100644 --- a/test/vm.js +++ b/test/vm.js @@ -49,3 +49,11 @@ test('vmRunInContext with closure', function (t) { t.equal(context.x, 2); t.equal(typeof context.y, 'function'); }); + +test('isContext', function (t) { + t.plan(2); + + var context = vm.createContext(); + t.true(vm.isContext(context)); + t.false(vm.isContext({})); +}); From df999fabdc505af9c2f39b4b6c66f9f38cb8587a Mon Sep 17 00:00:00 2001 From: Jacob Beard Date: Tue, 16 Aug 2016 22:32:21 -0400 Subject: [PATCH 7/8] Updated version number --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index dd948a2..9f97236 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "vm-browserify", - "version": "0.0.4", + "name": "vm-browserify2", + "version": "0.0.5", "description": "vm module for the browser", "main": "index.js", "repository": { From d25cc78699e11cfe910e971508594bb8712b9995 Mon Sep 17 00:00:00 2001 From: Jacob Beard Date: Tue, 16 Aug 2016 22:52:13 -0400 Subject: [PATCH 8/8] Remove readonly Infinity --- index.js | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 0be98c2..971c8b6 100644 --- a/index.js +++ b/index.js @@ -35,7 +35,7 @@ var defineProp = (function() { }()); var globals = ['Array', 'Boolean', 'Date', 'Error', 'EvalError', 'Function', -'Infinity', 'JSON', 'Math', 'NaN', 'Number', 'Object', 'RangeError', +'JSON', 'Math', 'NaN', 'Number', 'Object', 'RangeError', 'ReferenceError', 'RegExp', 'String', 'SyntaxError', 'TypeError', 'URIError', 'decodeURI', 'decodeURIComponent', 'encodeURI', 'encodeURIComponent', 'escape', 'eval', 'isFinite', 'isNaN', 'parseFloat', 'parseInt', 'undefined', 'unescape']; diff --git a/package.json b/package.json index 9f97236..1ce62dc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vm-browserify2", - "version": "0.0.5", + "version": "0.0.6", "description": "vm module for the browser", "main": "index.js", "repository": {