Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Run require(x) in a new VM sandbox #761

Closed
ORESoftware opened this issue Jul 29, 2017 · 12 comments
Closed

Run require(x) in a new VM sandbox #761

ORESoftware opened this issue Jul 29, 2017 · 12 comments

Comments

@ORESoftware
Copy link

ORESoftware commented Jul 29, 2017

I am looking at the VM module
https://nodejs.org/api/vm.html

I'd like to essentially run this code in a sandbox:

let sandBox  = {foo:'bar'};
vm.createContext(sandBox);

vm.runInNewContext('function(){' +
    'const foo = require('./some-other-file');' +
'}', sandBox);

my question is - how do load another JS file and run that new JS file in a new global context? My guess is that require() is not available in the VM string code, so how can I load the code and pass the appropriate values to the file? (__filename, __dirname, module, etc).

@ORESoftware
Copy link
Author

ORESoftware commented Jul 29, 2017

For example, if I do this:

const vm = require('vm');
const fs = require('fs');

const sandBox = vm.createContext({foo:'bar'});
const file = fs.readFileSync(__dirname + '/adjacent-file.js');

vm.runInContext(file, sandBox);

I get an error:

evalmachine.<anonymous>:3
const foo = require('./some-other-file');
              ^
ReferenceError: require is not defined
    at evalmachine.<anonymous>:3:15
    at ContextifyScript.Script.runInContext (vm.js:32:29)
    at Object.exports.runInContext (vm.js:64:17)

@ORESoftware
Copy link
Author

Is this the best way to do it:

https://stackoverflow.com/questions/20899863/the-module-property-is-undefined-when-using-vm-runinthiscontext

and if so, why don't the Node.js docs demonstrate an example of this?

@tniessen
Copy link
Member

If you need to access parts of the current scope, why do you use the vm module at all? (Just out of curiousity).

If you really want to do this, you will need to put a wrapper function around your code, which provides implementations of require, module etc. You might want to take a look at this function.

@bnoordhuis
Copy link
Member

For more, hah, context: require() loads code in its home context, you can't use it with vm.runInNewContext() (well, you can, but it won't do what you want.)

@refack
Copy link

refack commented Jul 30, 2017

Question

what's wrong with adding require to the sandbox?

> var sandBox1 = vm.createContext({foo:'bar', require});
undefined
> vm.runInNewContext('const path2 = require("path"); path2.join(foo, "b")', sandBox1);
'bar\\b'
> path2
ReferenceError: path2 is not defined

@ORESoftware
Copy link
Author

ORESoftware commented Jul 30, 2017

@tniessen I am looking to isolate code for the purposes of testing. I have multiple tests in the same process, and as opposed to forking processes, I am looking to the vm module to see if I can isolate shared scope.

@refack
Copy link

refack commented Jul 30, 2017

@tniessen I am looking to isolate code for the purposes of testing. I have multiple tests in the same process, and as opposed to forking processes, I am looking to the vm module to see if I can isolate shared scope.

@ORESoftware If you manage please share, I'm looking into improving core's test harness nodejs/node#14214

@ORESoftware
Copy link
Author

@refack yeah I will share - they are attempting to do the same thing over at AVA. Not sure how much success they have had so far.

avajs/ava#1332

I'd like to be notified if anyone "gets this working" :)

@Bartozzz
Copy link

Got the same problem. I am creating a simple package manager for one of my nw.js apps - Qilin. I need to load plugins from user desktop directly into nw.js context. Basically it tries to require plugins from the app whereas it should look directly into plugin directories.


You can find the manager itself here, but here are some core parts. The lifecycle is very basic:

  1. Download package from GitHub to a local directory;
  2. Build downloaded package using NPM (npm i, npm prepare, …);
  3. Load package (grab the exported variable);
const data:Object = await readPackage(dir);
const file:string = await readFile(exe, "utf8");

const script = new vm.Script(file, {
  filename: exe,
});

return {
  createContext: (ctx) => {
    return vm.createContext({
      ...ctx,
      __filename: exe,
      __dirname: dir,
      exports: exports,
      require: require,
      module: module,
    });
  },
  runInContext: (ctx) => script.runInContext(ctx),
};

Error:

{ module.js:529
    throw err;
    ^

Error: Cannot find module 'merge-descriptors'
    at Function.Module._resolveFilename (module.js:527:15)
    at Function.Module._load (module.js:476:23)
    at Module.require (module.js:568:17)
    at require (internal/module.js:11:18)
    at /Users/Bartek/Documents/GitHub/qilin-manager/demo/packages/plugins/crawlerr-master/dist/index.js:7:25
    at ContextifyScript.Script.runInContext (vm.js:59:29)
    at Object.runInContext (/Users/Bartek/Documents/GitHub/qilin-manager/dist/lib/load.js:44:23)
    at Manager.load.then (/Users/Bartek/Documents/GitHub/qilin-manager/demo/index.js:21:24)
    at <anonymous> code: 'MODULE_NOT_FOUND' }

@gireeshpunathil
Copy link
Member

is this still outstanding?

@gireeshpunathil
Copy link
Member

closing due to inactivity, please re-open if it is still outstanding.

@aggregate1166877
Copy link

Don't know if this will help anyone else, I'm using the following for an interactive shell tool I'm making:

const vm = require('vm');

// Create the VM context.
const context = vm.createContext(global);

// Bind require to the parent's require.
context.require = function(moduleName) {
  return eval(`require`)(moduleName);
}.bind(global);

// Run some code.
vm.runInContext(`
  const fs = require('fs');
  console.log(
    fs.readdirSync('/'),
  );
`, context);

This script can also require other JS files with both absolute and relative paths, and those scripts can require their own things as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants