Oleg
Oleg

Reputation: 9359

Run js code in a separate context and access its global variable

I would like to run a third-party JavaScript file (I don't have much control over its contents) in node and access a global variable created by that file's code in its context.

There are two things I've considered:

  1. Running the code in a vm sandbox. The problem is that I don't know how to properly create the context, because vm.createContext([sandbox]) won't automatically provide basic things such as console or require or whatever to the script I want to run.

    This is a bit of a bummer, because the documentation explicitly states (emphasis mine):

    If given a sandbox object, will "contextify" that sandbox so that it can be used in calls to vm.runInContext() or script.runInContext(). Inside scripts run as such, sandbox will be the global object, retaining all its existing properties but also having the built-in objects and functions any standard global object has.

    What are "the built-in objects and functions any standard global object has"? I'm naively assuming it's things like console, process, require, etc. But if so, the API doesn't work, because those are not set. I'm probably misunderstanding something here.

    var sandbox = vm.createContext({foo: 'foo'});
    var code = 'console.log(foo);';
    vm.runInContext(code, sandbox);
    

    Which results in:

    evalmachine.:1
    console.log(foo);
    ^
    ReferenceError: console is not defined

  2. Running the code in a child process. But I can't find any documentation on accessing global variables of child processes. I'm assuming the only way to communicate with a child process is by message passing, but even that seems to be from parent to child, not the other way round...

Basically, I'm stuck. Halp.

Upvotes: 13

Views: 3777

Answers (3)

Syed Umer Hasan
Syed Umer Hasan

Reputation: 764

In this code, we can send any of the response and can access the global variable with global function and can access the whole data returning from VM Sandbox.

 function compiler(){
     let add = x*y
     Return (add);
 }
 compiler();

const vm = new NodeVM({
   sandbox: {
     Return(data) {
       console.log('Data:', data);
     },
     x : 10,=
     y : 20
   },
   require: {
     external: true,
     builtin: ["fs", "path"],
     root: "./",
     mock: {
       fs: {
         readFileSync() {
           return "Nice try!";
         }
       }
     }
   }
 });
 try {
   vm.run(req.query.code);
 } catch (error) {
   console.log("error: ", error);
 }

Upvotes: 0

Oliver Salzburg
Oliver Salzburg

Reputation: 22099

How about just passing the parent's console in a context?

const vm = require('vm');

var sandbox = {
  console: console
};

var context = new vm.createContext(sandbox);
var script = new vm.Script('console.log("foo")');

script.runInContext(context);

Upvotes: 0

stdob--
stdob--

Reputation: 29172

You can use advanced vm/sandbox for Node.js

var VM = require('vm2').NodeVM; // https://github.com/patriksimek/vm2#nodevm

var options = {
    console: 'inherit',
    sandbox: {
        foo: 'foo'
    }
}

vm = new VM(options);

var code = `
    console.log(foo); 
    oldFoo = foo; 
    foo = Math.random();
`;

vm.run(code);

console.log(vm.context.oldFoo, vm.context.foo);

Upvotes: 5

Related Questions