Skip to content

lyzidiamond/terrarium

Repository files navigation

terrarium

build status

Terrarium is a sandbox for running JavaScript code with instrumentation. It's designed for interactive, learnable programming environments, but architecturally is more similar to code coverage tools.

Terrarium is not a security sandbox and is trivially easy to exploit.

How it Works

parse: Terrarium accepts a string of JavaScript source code. It parses this code with esprima. If this parse fails, it emits an error with the esprima-generated syntax error: this lets us normalize this class of errors across browsers and node versions.

transform: It then uses js-traverse to walk every node in the esprima-generated AST, finding comment nodes. Each comment is transformed into an instrumentation call. In node, that means using process.send.

generate: This AST is then turned back into JavaScript by escodegen.

run: The resulting JavaScript is run by either an iframe, or by process.fork, as specified below.

API

Terrarium provides two APIs: Terrarium.Browser and Terrarium.Node. They have the same behavior on separate platforms.

  • Browser runs code in a web browser by using an iframe and calling functions in window.top
  • Node runs code in a subprocess by using .fork and calling process.send

Terrarium.Browser is designed to be used with browserify.

The Terrarium.Browser API also accepts an options object to its constructor. The options include:

  • sandbox: an object of JavaScript objects to be transferred into the running context.

Export Modes

The instrument method that forms the core of Terrarium supports five formatting options:

instrumenting:

  • node: use process.send for messages
  • browser: wrap in window.run, assign window.error, use window.top for messages

exporting:

  • node-export: use console.log for messages
  • browser-export: use console.log for messages
  • browser-export-fancy: use console.log for messages and Mapbox for maps.

Example

var t = new Terrarium.Browser();
// or var t = new Terrarium.Node();

t.on('data', function(data) { /* instrumentation */ });
t.on('err', function(data) { /* errors */ });

t.run(JAVASCRIPT_SOURCE);

// later...
t.destroy(); // shut down

FAQ

  • Why not vm.runInContext: this was the previous approach. Terrarium now uses a child process because this allows it to bind to ports and effectively cancel listeners on close.
  • Why not eval(): eval doesn't provide variable sandboxing, so it's easy to overwrite existing variables on your page. It also doesn't allow you to control timers.

See Also

About

a sandbox for running JavaScript code with instrumentation

Resources

Stars

Watchers

Forks

Packages

No packages published