| module.exports = ` | ||
| <!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> | ||
| <meta charset="UTF-8"><script type="text/javascript"> | ||
| (function (win) { | ||
| var init = function (e) { | ||
| win.removeEventListener('message', init); | ||
| // eslint-disable-next-line no-eval | ||
| (e && e.data && (typeof e.data.__init_uvm === 'string')) && eval(e.data.__init_uvm); | ||
| }; | ||
| win.addEventListener('message', init); | ||
| }(window)); | ||
| </script> | ||
| </head></html>`; |
| (typeof window !== 'undefined' ? describe : describe.skip)('custom iframe in browser', function () { | ||
| var uvm = require('../../lib'), | ||
| firmware = require('../../firmware/sandbox-base'), | ||
| iframe; | ||
| beforeEach(function (done) { | ||
| iframe = document.createElement('iframe'); | ||
| iframe.setAttribute('src', 'data:text/html;base64, ' + | ||
| btoa(unescape(encodeURIComponent(firmware)))); | ||
| iframe.addEventListener('load', function () { | ||
| done(); | ||
| }); | ||
| document.body.appendChild(iframe); | ||
| }); | ||
| it('must load and dispatch messages', function (done) { | ||
| uvm.spawn({ | ||
| _sandbox: iframe, | ||
| bootCode: ` | ||
| bridge.on('loopback', function (data) { | ||
| bridge.dispatch('loopback', data); | ||
| }); | ||
| ` | ||
| }, function (err, context) { | ||
| if (err) { return done(err); } | ||
| context.on('loopback', function (data) { | ||
| expect(data).be('this should return'); | ||
| done(); | ||
| }); | ||
| context.dispatch('loopback', 'this should return'); | ||
| }); | ||
| }); | ||
| afterEach(function () { | ||
| iframe.parentNode.removeChild(iframe); | ||
| iframe = null; | ||
| }); | ||
| }); |
@@ -33,10 +33,9 @@ /* | ||
| */ | ||
| sandboxCode = function (code, id) { | ||
| return `<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> | ||
| <meta charset="UTF-8"> | ||
| <script type="text/javascript"> | ||
| sandboxCode = function (code, id, firmwareOnly) { | ||
| var firmware = ` | ||
| __uvm_emit = function (args) {window.parent.postMessage({__id_uvm: "${id}",__emit_uvm: args}, "*");}; | ||
| </script> | ||
| <script type="text/javascript">${code}</script> | ||
| <script type="text/javascript">(function (emit, id) { | ||
| try {${code}} catch (e) { setTimeout(function () { throw e; }, 0); } | ||
| (function (emit, id) { | ||
| window.addEventListener("message", function (e) { | ||
@@ -47,4 +46,9 @@ (e && e.data && (typeof e.data.__emit_uvm === 'string') && (e.data.__id_uvm === id)) && | ||
| }(__uvm_dispatch, "${id}")); | ||
| __uvm_dispatch = null; __uvm_emit = null;</script> | ||
| </head></html>`; | ||
| __uvm_emit('["load.${id}"]'); | ||
| __uvm_dispatch = null; __uvm_emit = null; | ||
| `; | ||
| return firmwareOnly ? firmware : `<!DOCTYPE html><html><head> | ||
| <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"><meta charset="UTF-8"> | ||
| <script type="text/javascript">${firmware}</script></head></html>`; | ||
| }; | ||
@@ -68,3 +72,3 @@ | ||
| processCallback = function () { | ||
| iframe.removeEventListener(LOAD, processCallback); | ||
| !options._sandbox && iframe.removeEventListener(LOAD, processCallback); | ||
@@ -83,12 +87,3 @@ bridge._dispatch = function () { | ||
| window.addEventListener(MESSAGE, forwardEmits); | ||
| iframe.addEventListener(LOAD, processCallback); // removed right when executed | ||
| // prepare an iframe as context | ||
| _.forEach(sandboxAttributes, function (val, prop) { | ||
| iframe.setAttribute(prop, val); | ||
| }); | ||
| // add HTML and bootstrap code to the iframe | ||
| iframe.setAttribute('src', 'data:text/html;base64, ' + btoa(unescape(encodeURIComponent(sandboxCode(code, id))))); | ||
| // equip bridge to disconnect (i.e. delete the iframe) | ||
@@ -98,2 +93,3 @@ bridge._disconnect = function () { | ||
| // remove the message handler for this sandbox | ||
| window.removeEventListener(MESSAGE, forwardEmits); | ||
@@ -106,4 +102,26 @@ | ||
| // if sandbox element is provided, we simply need to init with firmware code and wait for load event to be fired | ||
| if (options._sandbox) { | ||
| bridge.once('load.' + id, processCallback); // on load attach the dispatcher | ||
| iframe.contentWindow.postMessage({ | ||
| __init_uvm: sandboxCode(code, id, true) // the last `true` param indicates firmwareOnly | ||
| }, TARGET_ALL); | ||
| return; | ||
| } | ||
| // this point onwards, it is our own iframe, so we do all the appending and other stuff to DOM | ||
| iframe.addEventListener(LOAD, processCallback); // removed right when executed | ||
| // prepare an iframe as context | ||
| _.forEach(sandboxAttributes, function (val, prop) { | ||
| iframe.setAttribute(prop, val); | ||
| }); | ||
| // add HTML and bootstrap code to the iframe | ||
| iframe.setAttribute('src', 'data:text/html;base64, ' + btoa(unescape(encodeURIComponent(sandboxCode(code, id))))); | ||
| // now append the iframe to start processing stuff | ||
| document.body.appendChild(iframe); | ||
| }; |
+20
-8
@@ -9,2 +9,3 @@ var vm = require('vm'), | ||
| UVM_DATA_ = '__uvm_data_', | ||
| UVM_DISPATCH_ = '__uvm_dispatch_', | ||
@@ -83,4 +84,5 @@ /** | ||
| finally { // set all raw interface methods to null (except the dispatcher since we need it later) | ||
| context.__uvm_emit = null; | ||
| vm.runInContext('__uvm_emit = null;', context); | ||
| vm.runInContext('__uvm_emit = null; __uvm_dispatch = null;', context); | ||
| delete context.__uvm_emit; | ||
| delete context.__uvm_dispatch; | ||
| } | ||
@@ -90,13 +92,20 @@ | ||
| emitter._dispatch = function () { | ||
| var id = UVM_DATA_ + randomNumber(); | ||
| var id = UVM_DATA_ + randomNumber(), | ||
| dispatchId = UVM_DISPATCH_ + id; | ||
| try { | ||
| // precautionary restore of the dispatcher in case it's gone! | ||
| !context.__uvm_dispatch && (context.__uvm_dispatch = bridgeDispatch); | ||
| // save the data in context. by this method, we avoid needless string and character encoding or escaping | ||
| // issues. this is slightly prone to race condition issues, but using random numbers we intend to solve it | ||
| context[id] = jsonArray(arguments); | ||
| context[dispatchId] = bridgeDispatch; | ||
| vm.runInContext(`__uvm_dispatch(String(${id})); (delete ${id});`, context, { | ||
| // restore the dispatcher for immediate use! | ||
| vm.runInContext(` | ||
| (function (dispatch, data) { | ||
| ${id} = null; (delete ${id}); | ||
| ${dispatchId} = null; (delete ${dispatchId}); | ||
| dispatch(String(data)); | ||
| }(${dispatchId}, ${id})); | ||
| `, context, { | ||
| timeout: options.dispatchTimeout | ||
@@ -107,3 +116,6 @@ }); | ||
| catch (e) { this.emit(ERROR, e); } | ||
| finally { delete context[id]; } | ||
| finally { // precautionary delete | ||
| delete context[id]; | ||
| delete context[dispatchId]; | ||
| } | ||
| }; | ||
@@ -110,0 +122,0 @@ |
+1
-1
| { | ||
| "name": "uvm", | ||
| "version": "1.3.0-beta.1", | ||
| "version": "1.3.0", | ||
| "description": "Universal Virtual Machine for Node and Browser", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -48,2 +48,25 @@ describe('uvm errors', function () { | ||
| it('must not allow bridge raw interfaces to be accessed', function (done) { | ||
| uvm.spawn({ | ||
| bootCode: ` | ||
| bridge.on('probe', function () { | ||
| bridge.dispatch('result', { | ||
| typeofEmitter: typeof __uvm_emit, | ||
| typeofDispatcher: typeof __uvm_dispatch | ||
| }); | ||
| }); | ||
| ` | ||
| }, function (err, context) { | ||
| if (err) { return done(err); } | ||
| context.on('error', done); | ||
| context.on('result', function (test) { | ||
| expect(test).be.an('object'); | ||
| expect(test).not.have.property('typeofEmitter', 'function'); | ||
| expect(test).not.have.property('typeofDispatcher', 'function'); | ||
| done(); | ||
| }); | ||
| context.dispatch('probe'); | ||
| }); | ||
| }); | ||
| it('must allow escape sequences in arguments to be dispatched', function (done) { | ||
@@ -50,0 +73,0 @@ uvm.spawn({ |
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
88826
4.35%39
5.41%1520
6.52%0
-100%2
Infinity%