[
  {
    "path": ".gitignore",
    "content": "node_modules\n.DS_store\ntest.sh\ntest.js\nnohup.out\nout.txt\n\n/coverage.html"
  },
  {
    "path": ".travis.yml",
    "content": "language: node_js\nnode_js:\n  - \"0.10\"\n  - \"0.12\"\n  - \"iojs\"\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "Copyright (c) 2012 Benjamin Coe\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "README.md",
    "content": "SandCastle\n==========\n\n[![Build Status](https://travis-ci.org/bcoe/sandcastle.png)](https://travis-ci.org/bcoe/sandcastle)\n\nA simple and powerful sandbox for running untrusted JavaScript.\n\nThe Impetus\n-----------\n\nFor a project I'm working on, I needed the ability to run untrusted JavaScript code.\n\nI had a couple specific requirements:\n\n* I wanted the ability to whitelist an API for inclusion within the sandbox.\n* I wanted to be able to run multiple untrusted scripts in the same sandboxed subprocess.\n* I wanted good error reporting and stack-traces, when a sandboxed script failed.\n\nI could not find a library that met all these requirements, enter SandCastle.\n\nWhat Makes SandCastle Different?\n---------------------\n\n* It allows you to queue up multiple scripts for execution within a single sandbox.\n  * This better suits Node's evented architecture.\n* It provides reasonable stack traces when the execution of a sandboxed script fails.\n* It allows an API to be provided to the sandboxed script being executed.\n* It provides all this in a simple, well-tested, API.\n\nInstallation\n------------\n\n```bash\nnpm install sandcastle\n```\n\nCreating and Executing a Script\n----------------------\n\n```javascript\nvar SandCastle = require('sandcastle').SandCastle;\n\nvar sandcastle = new SandCastle();\n\nvar script = sandcastle.createScript(\"\\\n  exports.main = function() {\\\n    exit('Hey ' + name + ' Hello World!');\\\n  }\\\n\");\n\nscript.on('exit', function(err, output) {\n    console.log(output); // Hello World!\n});\n\nscript.run({name: 'Ben'});// we can pass variables into run.\n```\n\n__Outputs__\n\n```bash\nHey Ben Hello World!\n```\n\n* __exit(output):__ from within untrusted code, causes a sandboxed script to return.\n  * Any JSON serializable data passed into __exit()__ will be passed to the output parameter of an __exit__ event.\n* __on('exit'):__ this event is called when an untrusted script finishes execution.\n* __run()__ starts the execution of an untrusted script.\n\n\nSandCastle Options\n----------------------\n\nThe following options may be passed to the SandCastle constructor:\n\n* `timeout` &mdash; number of milliseconds to allow script to run (defaults to 5000 ms)\n* `memoryLimitMB` &mdash; maximum amount of memory that a script may consume  (defaults to 0)\n* `useStrictMode` &mdash; boolean; when true script runs in strict mode (defaults to false)\n* `api` &mdash; path to file that defines the API accessible to script\n* `cwd` &mdash; path to the current working directory that the script will be run in (defaults to `process.cwd()`)\n* `spawnExecPath` &mdash; path to a external node binary to run the sandbox with. (defaults to `process.execPath`) _This is a [temporary workaround](https://github.com/rogerwang/node-webkit/issues/213) which allows you to run the sandbox within [node-webkit](https://github.com/rogerwang/node-webkit)_\n* `refreshTimeoutOnTask` &mdash; boolean; refreshes the timeout whenever an answer to a task will be sent to the script\n\n\nExecuting Scripts on Pool of SandCastles\n----------------------\nA pool consists of several SandCastle child-processes, which will handle the script execution. Pool-object is a drop-in replacement of single Sandcastle instance. Only difference is, when creating the Pool-instance.\n\nYou can specify the amount of child-processes with parameter named numberOfInstances (default = 1).\n```javascript\nvar Pool = require('sandcastle').Pool;\n\nvar poolOfSandcastles = new Pool( { numberOfInstances: 3 }, { timeout: 6000 } );\n\nvar script = poolOfSandcastles.createScript(\"\\\n  exports.main = function() {\\\n    exit('Hello World!');\\\n  }\\\n\");\n\nscript.on('exit', function(err, output) {\n    console.log(output);\n});\n\nscript.run();\n```\n\nHandling Timeouts\n-----------------------\n\nIf a script takes too long to execute, a timeout event will be fired:\n\n```javascript\nvar SandCastle = require('sandcastle').SandCastle;\n\nvar sandcastle = new SandCastle({ timeout: 6000 });\n\nvar script = sandcastle.createScript(\"\\\n  exports.main = function() {\\\n    while(true) {};\\\n  }\\\n\");\n\nscript.on('exit', function(err, output) {\n    console.log('this will never happen.');\n});\n\nscript.on('timeout', function() {\n    console.log('I timed out, oh what a silly script I am!');\n});\n\nscript.run();\n```\n\n__Outputs__\n\n```bash\nI timed out, oh what a silly script I am!\n```\n\nHandling Errors\n-----------------------\n\nIf an exception occurs while executing a script, it will be returned as the first parameter in an __on(exit)__ event.\n\n```bash\nvar SandCastle = require('sandcastle').SandCastle;\n\nvar sandcastle = new SandCastle();\n\nvar script = sandcastle.createScript(\"\\\n  exports.main = function() {\\n\\\n    require('fs');\\n\\\n  }\\\n\");\n\nscript.on('exit', function(err, output) {\n    console.log(err.message);\n    console.log(err.stack);\n});\n\nscript.run();\n```\n\n__Outputs__\n\n```bash\nrequire is not defined\nReferenceError: require is not defined\n    at Object.main ([object Context]:2:5)\n    at [object Context]:4:9\n    at Sandbox.executeScript (/Users/bcoe/hacking/open-source/sandcastle/lib/sandbox.js:58:8)\n    at Socket.<anonymous> (/Users/bcoe/hacking/open-source/sandcastle/lib/sandbox.js:16:13)\n    at Socket.emit (events.js:64:17)\n    at Socket._onReadable (net.js:678:14)\n    at IOWatcher.onReadable [as callback] (net.js:177:10)\n```\n\nProviding an API\n------------------------\n\nWhen creating an instance of SandCastle, you can provide an API. Functions within this API will be available inside of the untrustred scripts being executed.\n\n__An Example of an API:__\n\n```javascript\nvar fs = require('fs');\n\nexports.api = {\n  getFact: function(callback) {\n    fs.readFile('./examples/example.txt', function (err, data) {\n      if (err) throw err;\n      callback(data.toString());\n    });\n  },\n  setTimeout: function(callback, timeout) {\n    setTimeout(callback, timeout);\n  }\n}\n```\n\n__A Script Using the API:__\n\n```javascript\nvar SandCastle = require('sandcastle').SandCastle;\n\nvar sandcastle = new SandCastle({\n  api: './examples/api.js'\n});\n\nvar script = sandcastle.createScript(\"\\\n  exports.main = function() {\\\n    getFact(function(fact) {\\\n      exit(fact);\\\n    });\\\n  }\\\n\");\n\nscript.on('exit', function(err, result) {\n  equal(result, 'The rain in spain falls mostly on the plain.', prefix);\n  sandcastle.kill();\n  finished();\n});\n\nscript.run();\n```\n\nExporting Multiple Functions\n------------------------\n\nRather than main, you create a script file that exports multiple methods.\n_Notice that one extra parameter `methodName` is available within the callback functions._\n\n```javascript\nvar SandCastle = require('sandcastle').SandCastle;\n\nvar sandcastle = new SandCastle();\n\nvar script = sandcastle.createScript(\"\\\n  exports = {\\\n  \tfoo: function() {\\\n      exit('Hello Foo!');\\\n    },\\\n    bar: function() {\\\n      exit('Hello Bar!');\\\n    },\\\n    hello: function() {\\\n      exit('Hey ' + name + ' Hello World!');\\\n    }\\\n  }\\\n\");\n\nscript.on('timeout', function(methodName) {\n\tconsole.log(methodName);\n});\n\nscript.on('exit', function(err, output, methodName) {\n\tconsole.log(methodName); // foo, bar, hello\n});\n\n// take note that a single script should only be\n// executing a single method at a time.\nvar cb = null;\nasync.eachLimit(['foo', 'bar', 'hello'], 1, function(item, _cb) {\n  cb = _cb;\n  script.run(item, {name: 'Ben'});\n});\n```\n\nProviding Tasks\n------------------------\n\nIn contrast to the [API](#providing-an-api) which runs trusted code __inside__ the sandbox, the script can request that a task (a snippet of code) is executed in another process.\n\nTo run a task call `runTask(taskName, options = {})` and provide a `onTask(taskName, data)` method within the script file. Alternatively you can create a task specific function `on{TaskName}Task`, to receive data for an individual task.\n\n```javascript\nvar script = sandcastle.createScript(\"\\\n  exports = {\\\n    onGetContentTask: function (data) {\\\n      // received content. do something here...\n    },\\\n    main: function() {\\\n      runTask('getContent', {url: 'http://foo.bar'});\\\n    }\\\n  }\\\n\");\n\nscript.on('task', function (err, taskName, options, methodName, callback) {\n  if (whitelistedUrls.indexOf(options.url) !== -1) {\n    http.get(options.url, function(res) {\n      callback(res);\n    }).on('error', function(e) {\n      callback(null);\n    });\n  }\n});\n```\n\n`refreshTimeoutOnTask` can be used to control the timeout behavior of the script executing the task. If set to true, the script will have its timeout reset when the task is completed.\n\nDebugging\n---------\nMake debugging a little easier by ensuring the DEBUG environment variable includes `sandcastle`.\n\nContributing\n---------\n\nSandCastle will be an ongoing project, please be liberal with your feedback, criticism, and contributions.\n\n* send pull requests, for creative exploits that you find find for the SandBox. Sandboxing JavaScript is hard, it's unlikely that this library will ever be 100% bullet-proof.\n* write unit tests for your contributions!\n\nCopyright\n---------\n\nCopyright (c) 2012 Benjamin Coe. See LICENSE.txt for further details.\n"
  },
  {
    "path": "bin/sandcastle.js",
    "content": "#!/usr/bin/env node\n\nvar sandcastle = require('../lib'),\n  argv = require('optimist').argv,\n  mode = argv._.shift();\n\nswitch (mode) {\n  case 'sandbox':\n    (new sandcastle.Sandbox({\n        socket: (argv.socket || '/tmp/sandcastle.sock')\n    })).start();\n    break;\n  default:\n    console.log('Usage sandcastle <command>\\n\\n\\\n      \\t<sandbox>\\tstart a sandbox server\\n\\\n      \\t\\t--socket=[path to socket file]\\n\\\n    ')\n}"
  },
  {
    "path": "examples/api-example.js",
    "content": "// example of using an external API. In this case\n// we pul lin lodash's extend.\nvar SandCastle = require('../lib').SandCastle;\n\nvar sandcastle = new SandCastle({\n  api: './examples/api.js', // We provide an API with the setTimeout function.,\n});\n\nvar script = sandcastle.createScript(\"\\\n  exports.main = function() {\\\n    var o1 = {a: 2};\\\n    var o2 = {b: 3};\\\n    extend(o1, o2);\\\n    exit(JSON.stringify(o1));\\\n  }\\\n\");\n\nscript.on('exit', function(err, output) {\n    console.log(output); // Hello World!\n    process.exit(0);\n});\n\nscript.run();\n"
  },
  {
    "path": "examples/api.js",
    "content": "var fs = require('fs');\nvar lodash = require('lodash')\n\nexports.api = {\n  extend: function () {\n    lodash.extend.apply(this, arguments)\n  },\n  getFact: function(callback) {\n    fs.readFile('./examples/example.txt', function (err, data) {\n      if (err) throw err;\n      callback(data.toString());\n    });\n  },\n  setTimeout: function(callback, timeout) {\n    setTimeout(callback, timeout);\n  },\n  callAdditional: function(callback) {\n    anotherFunction(callback)\n  },\n  cwd: function() {\n    return process.cwd();\n  }\n}\n"
  },
  {
    "path": "examples/benchmark.js",
    "content": "var SandCastle = require('../lib').SandCastle,\n  equal = require('assert').equal;\n\nvar sandcastle = new SandCastle({\n  api: './examples/api.js', // We provide an API with the setTimeout function.,\n  timeout: 2000\n});\n\n(function execute(n) {\n\n  if (!n) {\n    process.exit(0);\n    return;\n  }\n\n  // Keep track of execution stats.\n  var stats = {\n    script1: 0,\n    script2: 0,\n    script3: 0\n  };\n\n  // A non-malicious script with a timeout.\n  var script1 = sandcastle.createScript(\"\\\n    exports.main = function() {\\\n      setTimeout(function() {\\\n        exit('script1')\\\n      }, 10)\\\n    }\\\n  \");\n\n  script1.on('exit', function(err, output) {\n    stats[output] += 1;\n  });\n\n  script1.on('timeout', function() {\n    // reschedule script1 when it times out.\n    script1.run();\n  });\n\n  // a malicious script that loops infinitely.\n  var script2 = sandcastle.createScript(\"\\\n    exports.main = function() {\\\n      while('script2') {};\\\n    }\\\n  \");\n\n  script2.on('exit', function(err, output) {\n    stats[output] += 1;\n  });\n\n  // A non-malicious script with a timeout.\n  var script3 = sandcastle.createScript(\"\\\n    exports.main = function() {\\\n      setTimeout(function() {\\\n        exit('script3')\\\n      }, 1000)\\\n    }\\\n  \");\n\n  script3.on('exit', function(err, output) {\n    stats[output] += 1;\n  });\n\n  script3.on('timeout', function() {\n\n    // reschedule script3 when it times out.\n\n    script3.removeAllListeners('exit');\n    script3.on('exit', function(err, output) {\n      stats.script3 += 1;\n      \n      // Make sure the scripts were\n      // executed the appropriate # of times.\n      equal(stats.script1, 2);\n      equal(stats.script2, 0);\n      equal(stats.script3, 2);\n      console.log('scripts executed the correct # of times', stats)\n      setTimeout(function() {\n        execute(n - 1);\n      }, 0);\n    });\n    script3.run();\n  });\n\n  // Running script 1 and 3 will take.\n  // about 2 seconds to complete.\n  script1.run();\n  script3.run();\n\n  var id = setInterval(function() {\n    if (script1.exited && script3.exited) {\n      clearInterval(id);\n\n      // both script1 and script 2 exited after their first execution.\n      // next we will schedule them with a malicious script.\n\n      script3.run();\n      script1.run();\n      // script2 is malicious and will cause the sandbox to shutdown\n      // script1 and script3's timeout methods however cause them to be\n      // rescheduled.\n      script2.run();\n    }\n  }, 1000);\n\n})(1000);"
  },
  {
    "path": "examples/contextObjectApi.js",
    "content": "\nvar StateManager = function(){\n\tvar state = contextObject.state;\n\n\tdelete contextObject.state;\n\n\tthis.getState=function(){\n\t\treturn state;\n\t};\n};\nexports.api = {\n\tstateManager: new StateManager()\n};\n"
  },
  {
    "path": "examples/error.js",
    "content": "var SandCastle = require('../').SandCastle;\n\nvar sandcastle = new SandCastle();\n\nvar script = sandcastle.createScript(\"\\\n  exports.main = function() {\\n\\\n    require('fs');\\n\\\n  }\\\n\");\n\nscript.on('exit', function(err, output) {\n    console.log(err.message);\n    console.log(err.stack);\n});\n\nscript.run();"
  },
  {
    "path": "examples/example.txt",
    "content": "The rain in spain falls mostly on the plain."
  },
  {
    "path": "examples/hello.js",
    "content": "var SandCastle = require('../lib').SandCastle;\n\nvar sandcastle = new SandCastle();\n\nvar script = sandcastle.createScript(\"\\\n  exports.main = function() {\\\n    exit('Hello World!');\\\n  }\\\n\");\n\nscript.on('exit', function(err, output) {\n    console.log(output); // Hello World!\n    process.exit(0);\n});\n\nscript.run();\n"
  },
  {
    "path": "examples/multiple-functions.js",
    "content": "var async = require('async'),\n  SandCastle = require('../lib').SandCastle,\n  sandcastle = new SandCastle();\n\nvar script = sandcastle.createScript(\"\\\n  exports = {\\\n    foo: function() {\\\n      exit('Hello Foo!');\\\n    },\\\n    bar: function() {\\\n      exit('Hello Bar!');\\\n    },\\\n    hello: function() {\\\n      exit('Hey ' + name + ' Hello World!');\\\n    }\\\n  }\\\n\");\n\nscript.on('timeout', function(methodName) {\n  console.log(methodName);\n});\n\nscript.on('exit', function(err, output, methodName) {\n  console.log(methodName, output); // foo, bar, hello\n  return cb();\n});\n\nvar cb = null;\n\nasync.eachLimit(['foo', 'bar', 'hello'], 1, function(item, _cb) {\n  cb = _cb;\n  script.run(item, {name: 'Ben'});\n});\n"
  },
  {
    "path": "examples/pool.js",
    "content": "var Pool = require('../lib').Pool;\n\n// You can give options for SandCastle instances with second parameter.\nvar poolOfSandcastles = new Pool( { numberOfInstances: 3 }, { useStrictMode: true } );\n\nvar script = poolOfSandcastles.createScript(\"\\\n  exports.main = function() {\\\n    exit('Hello World!');\\\n  }\\\n\");\n\nscript.on('exit', function(err, output) {\n    console.log(output);\n});\n\n\nvar script2 = poolOfSandcastles.createScript(\"\\\n  exports.main = function() {\\\n    exit('Hello World again!');\\\n  }\\\n\");\n\nscript2.on('exit', function(err, output) {\n  console.log(output);\n});\n\nscript.run();\nscript2.run();\n"
  },
  {
    "path": "examples/timeout.js",
    "content": "var SandCastle = require('../lib').SandCastle;\n\nvar sandcastle = new SandCastle();\n\nvar script = sandcastle.createScript(\"\\\n  exports.main = function() {\\\n    while(true) {};\\\n  }\\\n\");\n\nscript.on('exit', function(err, output) {\n    console.log('this will never happen.');\n});\n\nscript.on('timeout', function() {\n    console.log('I timed out, oh what a silly script I am!');\n});\n\nscript.run();\n"
  },
  {
    "path": "lib/index.js",
    "content": "exports.Pool = require('./pool').Pool;\nexports.SandCastle = require('./sandcastle').SandCastle;\nexports.Sandbox = require('./sandbox').Sandbox;"
  },
  {
    "path": "lib/pool.js",
    "content": "var _ = require('lodash'),\n  SandCastle = require(\"./sandcastle\").SandCastle;\n\nfunction Pool(opts, sandCastleCreationOpts) {\n  _.extend(this, {\n    numberOfInstances: 1\n  }, opts);\n\n  if(this.numberOfInstances < 1) {\n    throw \"Can't create a pool with zero instances\";\n  }\n\n  this.sandcastles = [];\n  this.runQueue = [];\n  this.consumerSleeping = true;\n\n  for(var i = 0; i < this.numberOfInstances; ++i) {\n    var sandCastleOptions = {}\n    _.extend( sandCastleOptions,\n              sandCastleCreationOpts,\n              { socket: '/tmp/sandcastle_' + i.toString() + '.sock' }\n            );\n\n    this.sandcastles.push({\n      castle: new SandCastle(sandCastleOptions),\n      running: false\n    });\n  }\n};\n\nPool.prototype.kill = function() {\n  this.sandcastles.forEach(function(sandcastleData) {\n    sandcastleData.castle.kill();\n  });\n}\n\nPool.prototype.consumeScript = function() {\n\n  if(this.runQueue && this.runQueue.length > 0) {\n    for(var i = 0; i < this.sandcastles.length; ++i) {\n\n      var sandcastleData = this.sandcastles[i];\n      if(!sandcastleData.running && sandcastleData.castle.isInitialized()) {\n        var nextScript = this.runQueue.splice(0,1)[0];\n        if(nextScript && nextScript.script) {\n          this.runOnSandCastle(nextScript.script, nextScript.globals, sandcastleData);\n        } else {\n          // No scripts on queue.\n          break;\n        }\n      }\n\n    }\n\n    setImmediate(function() {\n      this.consumeScript()\n    }.bind(this));\n    this.consumerSleeping = false;\n\n  } else {\n    this.consumerSleeping = true;\n  }\n}\n\nPool.prototype.runOnSandCastle = function(nextScript, scriptGlobals, sandcastleData) {\n  var _this = this;\n\n  sandcastleData.running = true;\n\n  nextScript.on('exit', function() {\n    sandcastleData.running = false;\n  });\n\n  nextScript.on('timeout', function() {\n    sandcastleData.running = false;\n  });\n\n  nextScript.setSandCastle(sandcastleData.castle);\n  nextScript.super_run(scriptGlobals);\n}\n\nPool.prototype.requestRun = function(script, scriptGlobals) {\n  this.runQueue.push({script: script, globals: scriptGlobals});\n  if(this.consumerSleeping) {\n    this.consumeScript();\n  }\n};\n\nPool.prototype.createScript = function(source, opts) {\n  var _this = this;\n\n  // All scripts are created from first sandbox, but the\n  // final target-sandbox is decided just before running.\n  var newScript = this.sandcastles[0].castle.createScript(source, opts);\n\n  // Override run-function, but keep the run function of superclass in\n  // super_run. This allows drop in placement of Pool in place of SandCastle.\n  newScript.super_run = newScript.run;\n  newScript.run = function (globals) {\n    _this.requestRun(newScript, globals);\n  }\n  return newScript;\n}\n\nexports.Pool = Pool;\n"
  },
  {
    "path": "lib/sandbox.js",
    "content": "var _ = require('lodash'),\n  net = require('net'),\n  vm = require('vm'),\n  BufferStream = require('bufferstream'),\n  clone = require('clone');\n\nfunction Sandbox(opts) {\n  _.extend(this, {\n    socket: '/tmp/sandcastle.sock'\n  }, opts);\n}\n\nSandbox.prototype.start = function() {\n  var _this = this;\n  var data = '';\n\n  this.server = net.createServer(function(c) {\n\n    var stream = new BufferStream({size:'flexible'});\n\n    // script begin\n    stream.split('\\u0000\\u0000', function(chunk) {\n      _this.executeScript(c, chunk);\n    });\n\n    // recieved answer\n    stream.split('\\u0000', function (chunk) {\n      _this.answerTask(c, chunk);\n    });\n\n    c.on('data', stream.write);\n  });\n\n  this.server.listen(this.socket, function() {\n    console.log('sandbox server created'); // emit data so that sandcastle knows sandbox is created\n  });\n\n  this.server.on('error', function() {\n    setTimeout(function() {\n      _this.start();\n    }, 500);\n  });\n};\n\nSandbox.prototype._sendError = function (connection, e, replaceStack) {\n  connection.write(JSON.stringify({\n      error: {\n        message: e.message,\n        stack: !replaceStack ? e.stack : e.stack.replace()\n      }\n    }) + '\\u0000\\u0000'); // exit/start separator\n};\n\nSandbox.prototype.answerTask = function(connection, data) {\n  var _this = this;\n\n  try {\n    var taskData = JSON.parse(data.toString()),\n      taskName = taskData.task,\n      onAnswerName = 'on' + taskName.charAt(0).toUpperCase() + taskName.slice(1) + 'Task';\n\n    if (this._ctx.exports[onAnswerName]) {\n      this._ctx.exports[onAnswerName](taskData.data);\n    }\n    else if (this._ctx.exports.onTask) {\n      this._ctx.exports.onTask(taskName, taskData.data);\n    }\n  }\n  catch (e) {\n    _this._sendError(connection, e);\n  }\n};\n\nSandbox.prototype.executeScript = function(connection, data) {\n  var contextObject = {\n      runTask: function (taskName, options) {\n        options = options || {};\n\n        try {\n          connection.write(JSON.stringify({\n            task: taskName,\n            options: options\n          }) + '\\u0000'); // task seperator\n        } catch(e) {\n          this._sendError(connection, e, false);\n        }\n      },\n      exit: function(output) {\n        try {\n          connection.write(JSON.stringify(output) + '\\u0000\\u0000'); // exit/start separator\n        } catch(e) {\n          _this._sendError(connection, e, true);\n        }\n      }\n    };\n\n  try {\n    var script = JSON.parse(data);\n\n\n    // The trusted global variables.\n    if (script.globals) {\n      var globals = JSON.parse(script.globals);\n\n      Object.keys(globals).forEach(function(key) {\n        contextObject[key] = globals[key];\n      });\n    }\n\n    // The trusted API.\n    if (script.sourceAPI) {\n      var api = eval(script.sourceAPI);\n\n      Object.keys(api).forEach(function(key) {\n        contextObject[key] = api[key];\n      });\n    }\n\n    // recursively clone contextObject without prototype,\n    // to prevent exploits using __defineGetter__, __defineSetter__.\n    // https://github.com/bcoe/sandcastle/pull/21\n    contextObject = clone(contextObject, true, Infinity, null);\n\n    this._ctx = vm.createContext(contextObject);\n\n    vm.runInNewContext( this.wrapForExecution(script.source, script.methodName), this._ctx);\n  } catch (e) {\n    this._sendError(connection, e, false);\n  }\n\n};\n\nSandbox.prototype.wrapForExecution = function(source, methodName) {\n  return \"var exports = Object.create(null);\" + source + \"\\nexports.\" + methodName + \"();\";\n};\n\nexports.Sandbox = Sandbox;\n"
  },
  {
    "path": "lib/sandcastle.js",
    "content": "var _ = require('lodash'),\n  Script = require('./script').Script,\n  path = require('path'),\n  fs = require('fs'),\n  os = require('os'),\n  debug = require('debug')('sandcastle'),\n  spawn = require( 'child_process' ).spawn;\n\nvar SIGHUP = os.platform()=='win32' ? 'SIGTERM' : 'SIGHUP';\n\nfunction SandCastle(opts) {\n  var _this = this;\n\n  _.extend(this, {\n    client: null,\n    api: null,\n    timeout: 5000,\n    sandbox: null,\n    lastHeartbeat: (new Date()).getTime(),\n    socket: '/tmp/sandcastle.sock',\n    useStrictMode: true,\n    memoryLimitMB: 0,\n    cwd: process.cwd(),\n    spawnExecPath: process.execPath,\n    refreshTimeoutOnTask: false\n  }, opts);\n\n  if (this.api) {\n    if (this.api.indexOf('{') !== -1) {\n      // allow the API to be passed in as a blob of source-code.\n      this.sourceAPI = this.api;\n    } else {\n      // otherwise, load the API from a file.\n      // expanding ./ to current working directory.\n      if (this.api.indexOf('.') === 0) this.api = path.join(this.cwd, this.api);\n      this.sourceAPI = fs.readFileSync(this.api, 'utf-8');\n    }\n  }\n\n  this.spawnSandbox();\n  this.startHeartbeat();\n\n  // Shutdown the sandbox subprocess.\n  // when the sandcastle process is terminated.\n  process.on('exit', function() {\n    _this.sandbox.kill(SIGHUP);\n  });\n}\n\nSandCastle.prototype.sandboxReady = function(callback) {\n  var _this = this;\n  if (this.sandboxInitialized) {\n    callback();\n  } else {\n    setTimeout(function() {\n      _this.sandboxReady(callback);\n    }, 500);\n  }\n};\n\nSandCastle.prototype.kickOverSandCastle = function() {\n  if(this.sandboxInitialized) {\n    this.sandboxInitialized = false;\n    this.sandbox.kill(SIGHUP);\n  }\n};\n\nSandCastle.prototype.spawnSandbox = function() {\n\n  var _this = this;\n\n  // attempt to unlink the old socket.\n  try {fs.unlinkSync(this.socket)} catch (e) {};\n\n  this.sandbox = spawn(this.spawnExecPath, [\n    _this.useStrictMode ? \"--use_strict\" : \"--nouse_strict\",\n    \"--max_old_space_size=\" + _this.memoryLimitMB.toString(),\n    __dirname + '/../bin/sandcastle.js',\n    'sandbox',\n    '--socket=' + this.socket\n  ], {cwd: _this.cwd});\n\n  // Assume that the sandbox is created once\n  // data is emitted on stdout.\n  this.sandbox.stdout.on('data', function(data) {\n    debug(\"Sandbox output: \" + data.toString());\n    _this.waitingOnHeartbeat = false; // Used to keep only one heartbeat on the wire at a time.\n    _this.sandboxInitialized = true;\n  });\n\n  this.sandbox.stderr.on('data', function(data) {\n    debug(\"Sandbox error: \" + data.toString());\n    _this.waitingOnHeartbeat = false;\n  });\n\n  this.sandbox.on('exit', function (code) {\n    _this.spawnSandbox();\n  });\n\n};\n\nSandCastle.prototype.kill = function() {\n  clearInterval(this.heartbeatId);\n  this.sandbox.removeAllListeners('exit');\n  this.sandbox.kill(SIGHUP);\n  process.removeAllListeners('exit');\n};\n\nSandCastle.prototype.startHeartbeat = function() {\n  var _this = this;\n\n  _this.heartbeatId = setInterval(function() {\n    var now = (new Date()).getTime();\n\n    _this.runHeartbeatScript();\n\n    if ( (now - _this.lastHeartbeat) > _this.timeout) {\n      _this.lastHeartbeat = (new Date()).getTime();\n      _this.kickOverSandCastle();\n    }\n  }, 500);\n\n};\n\nSandCastle.prototype.runHeartbeatScript = function() {\n\n  // Only wait for one heartbeat script\n  // to execute at a time.\n  if (this.waitingOnHeartbeat) return;\n  this.waitingOnHeartbeat = true;\n\n  var _this = this,\n    script = this.createScript(\"exports.main = function() {exit(true)}\");\n\n  script.on(\"exit\", function(err, output) {\n    if (output) {\n      _this.lastHeartbeat = (new Date()).getTime();\n      _this.waitingOnHeartbeat = false;\n    }\n  });\n\n  script.run('main');\n};\n\nSandCastle.prototype.createScript = function(source, opts) {\n  var sourceAPI = this.sourceAPI || '';\n  if (opts && opts.extraAPI) sourceAPI += \";\\n\" + opts.extraAPI\n\n  return new Script({\n    source: source,\n    sourceAPI: sourceAPI,\n    timeout: this.timeout,\n    socket: this.socket,\n    sandcastle: this\n  });\n};\n\nSandCastle.prototype.isInitialized = function() {\n  return this.sandboxInitialized;\n}\n\nSandCastle.prototype.getSocket = function() {\n  return this.socket;\n}\n\nexports.SandCastle = SandCastle;\n"
  },
  {
    "path": "lib/script.js",
    "content": "var _ = require('lodash'),\n  net = require('net'),\n  events = require('events'),\n  util = require('util'),\n  BufferStream = require('bufferstream'),\n  Buffer = require('buffer').Buffer;\n\nfunction Script(opts) {\n  events.EventEmitter.call(this);\n  \n  _.extend(this, {\n    source: '',\n    socket: '/tmp/sandcastle.sock',\n    timeout: 5000,\n    exited: false,\n    sandcastle: null // the parent sandcastle executing this script.\n  }, opts);\n};\n\nutil.inherits(Script, events.EventEmitter);\n\nScript.prototype.run = function(methodName, globals) {\n  var _this = this;\n\n  // passed in methodName argument is the globals object\n  if (globals === undefined && typeof methodName === 'object') {\n    globals = methodName;\n    methodName = null;\n  }\n\n  // we default to executing 'main'\n  methodName = methodName ? methodName : 'main';\n\n  this.reset();\n\n  this.createTimeout(methodName);\n\n  this.createClient(methodName, globals);\n};\n\nScript.prototype.createTimeout = function(methodName) {\n  var _this = this;\n\n  if (this.timeoutId) clearTimeout(this.timeoutId);\n\n  this.timeoutId = setTimeout(function() {\n    if (_this.exited) return;\n    _this.exited = true;\n    _this.sandcastle.kickOverSandCastle();\n    _this.emit('timeout', methodName);\n  }, this.timeout);\n};\n\nScript.prototype.reset = function() {\n  if (this.timeoutId) clearTimeout(this.timeoutId);\n  this.exited = false;\n};\n\nScript.prototype.createClient = function(methodName, globals) {\n\n  var _this = this;\n\n  this.sandcastle.sandboxReady(function() {\n\n    if (_this.exited) return;\n\n    var client = net.createConnection(_this.sandcastle.getSocket(), function() {\n      client.write(JSON.stringify({\n        source: _this.source,// the untrusted JS.\n        sourceAPI: _this.sourceAPI,// the trusted API.\n        globals: JSON.stringify(globals), // trusted global variables.\n        methodName: methodName\n      }) + '\\u0000\\u0000'); // the chunk separator\n    });\n\n    client.on('close', function() {\n      if (!_this.dataReceived) {\n        setTimeout(function() {\n          _this.createClient(methodName, globals);\n        }, 500);\n      }\n    });\n\n    client.on('error', function(err) {\n      setTimeout(function() {\n        _this.createClient(methodName, globals);\n      }, 500);\n    });\n\n\n    var stream = new BufferStream({size:'flexible'});\n    stream.split('\\u0000\\u0000', function(chunk) {\n      client.end();\n      _this.onExit(methodName, chunk);\n    });\n\n    stream.split('\\u0000', function (chunk) {\n      _this.onTask(client, methodName, chunk); // handling the task\n    });\n\n    client.on('data', function(chunk) {\n      _this.dataReceived = true;\n      stream.write(chunk);\n    });\n\n  });\n};\n\nScript.prototype._parseChunk = function(data) {\n  var output = null,\n    error = null;\n\n  try {\n    if (data.toString() !== 'undefined') {\n        output = JSON.parse(data);\n        if (output !== null && output.error) {\n            error = new Error(output.error.message);\n            error.stack = output.error.stack;\n            output = null;\n        }\n    }\n  } catch (e) {\n    error = e;\n  }\n\n  return {\n    output: output,\n    error: error\n  };\n};\n\nScript.prototype.onExit = function(methodName, data) {\n  var _this = this,\n    parsed = {\n      output: null,\n      error: null\n    };\n\n  if (this.exited) return;\n\n  this.exited = true;\n\n  parsed = _this._parseChunk(data);\n\n  this.emit('exit', parsed.error, parsed.output, methodName);\n};\n\nScript.prototype.onTask = function(client, methodName, data) {\n  var _this = this,\n    parsed = _this._parseChunk(data);\n\n  if (this.exited) return;\n\n  parsed.output = parsed.output || {};\n  parsed.output.options = parsed.output.options || {};\n\n  this.emit('task', parsed.error, parsed.output.task, parsed.output.options, methodName, function (answerData) {\n    if (_this.refreshTimeoutOnTask) _this.createTimeout(methodName);\n    client.write(JSON.stringify({ task: parsed.output.task, data: answerData }) + '\\u0000');\n  });\n};\n\nScript.prototype.setSandCastle = function(sandcastle) {\n  this.sandcastle = sandcastle;\n};\n\nexports.Script = Script;\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"sandcastle\",\n  \"directories\": {\n    \"lib\": \"./lib\",\n    \"bin\": \"./bin\"\n  },\n  \"main\": \"./lib/index.js\",\n  \"bin\": \"./bin/sandcastle.js\",\n  \"version\": \"1.3.3\",\n  \"author\": \"Ben Coe <bencoe@gmail.com>\",\n  \"engines\": [\n    \"node\"\n  ],\n  \"description\": \"A simple and powerful sandbox for running untrusted JavaScript.\",\n  \"keywords\": [\n    \"sandbox\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/bcoe/sandcastle.git\"\n  },\n  \"scripts\": {\n    \"coverage\": \"./node_modules/.bin/mocha test/* --require blanket --colors --timeout=10000 -R html-cov > coverage.html\",\n    \"test\": \"mocha --timeout=10000 --check-leaks --ui exports --require patched-blanket -R mocoverage\"\n  },\n  \"config\": {\n    \"blanket\": {\n      \"pattern\": \"lib\",\n      \"data-cover-never\": [\n        \"node_modules\",\n        \"test\"\n      ],\n      \"output-reporter\": \"spec\"\n    }\n  },\n  \"dependencies\": {\n    \"bufferstream\": \"^0.6.2\",\n    \"clone\": \"^0.1.18\",\n    \"debug\": \"^2.1.2\",\n    \"lodash\": \"^2.4.1\",\n    \"optimist\": \"^0.3.4\"\n  },\n  \"devDependencies\": {\n    \"async\": \"^0.9.0\",\n    \"mocha\": \"2.1.0\",\n    \"mocoverage\": \"^1.0.0\",\n    \"patched-blanket\": \"^1.0.1\"\n  }\n}\n"
  },
  {
    "path": "test/exploits-test.js",
    "content": "var assert = require('assert'),\n  SandCastle = require('../lib').SandCastle,\n  fs = require('fs');\n\ndescribe('__defineGetter__-exploit', function () {\n  it('should not execute untrusted code as a result of __defineGetter_ exploit', function (finished) {\n    // fix for exploit: https://github.com/bcoe/sandcastle/pull/21\n    var sandcastle = new SandCastle(),\n      script = sandcastle.createScript(fs.readFileSync(\"./test/fixtures/exploit-getter.txt\").toString());\n\n    script.on('exit', function(err, output) {\n      setTimeout(function() {\n        sandcastle.kill();\n        assert.equal(fs.existsSync('./owned.txt'), false);\n        finished();\n      }, 2000);\n    });\n\n    script.run({parameters: {string: 'hello!'}});\n  });\n});\n\ndescribe('arguments.callee-exploit', function() {\n  it('should not execute untrusted code as a result of walking the arguments.callee chain', function(finished) {\n    // fix for exploit: https://github.com/bcoe/sandcastle/pull/21\n    var sandcastle = new SandCastle(),\n      script = sandcastle.createScript(fs.readFileSync(\"./test/fixtures/exploit-callee.txt\").toString());\n\n    setTimeout(function() {\n      sandcastle.kill();\n      assert.equal(fs.existsSync('./owned.txt'), false);\n      finished();\n    }, 2000);\n\n    script.run({parameters: {string: 'hello!'}});\n  });\n});\n"
  },
  {
    "path": "test/fixtures/exploit-callee.txt",
    "content": "exports.main = function() {\n        var payload = \"var fs = require('fs');fs.writeFileSync('owned.txt', 'You could have been owned now\\\\n');exports.api = {};\";\n        var jsonPayload = JSON.stringify({source:\";exports.main = function(){exit('ok')};\", sourceAPI:payload});\n\n        var retVal =\n        {\n            f: {}\n        };\n\n        retVal.__defineGetter__(\"f\", function() {\n            throw {\n                stack:\n                {\n                    replace: function() {\n                        var a = {};\n                        a.__defineGetter__(\"stack\", function() {\n                            // calls Sandbox.executeScript(connection, data)\n                            arguments.callee.caller(null, jsonPayload);\n                        });\n                        throw a;\n                    }\n                }\n            };\n        });\n\n        exit(retVal);\n}\n"
  },
  {
    "path": "test/fixtures/exploit-getter.txt",
    "content": "exports.main = function() {\n  var origSubstr = parameters.string.__proto__.substr;\n  var payload = \"var fs = require('fs');fs.writeFileSync('owned.txt', 'You could have been owned now\\\\n');\";\n  var jsonPayload = JSON.stringify({source:\";exports.main = function(){exit('ok')};\", sourceAPI:payload});\n  var defineGetter = parameters.__defineGetter__;\n  var defineSetter = parameters.__defineSetter__;\n\n  defineSetter.call(parameters.__proto__, 'data', function(val) {\n    this.__hidden_data = val;\n  });\n  defineGetter.call(parameters.__proto__, 'data', function() {\n    var chained = this.__hidden_data;\n    if (typeof chained != \"function\")\n      return chained;\n    return function(data) {\n      return chained.call(this, jsonPayload + '\\u0000');\n    };\n  });\n\n  exit('ok');\n}\n"
  },
  {
    "path": "test/pool-test.js",
    "content": "var equal = require('assert').equal,\n  notEqual = require('assert').notEqual,\n  Pool = require('../lib').Pool;\n\ndescribe('Pool', function () {\n  it('should run multiple scripts', function (finished) {\n    var pool = new Pool({numberOfInstances: 5});\n\n    var scriptsExited = 0;\n\n    for (var i = 0; i < 20; ++i) {\n      var script = pool.createScript(\"\\\n          exports.main = function() {\\n\\\n            exit(testGlobal);\\n\\\n          }\\n\\\n        \"\n      );\n      script.on('exit', function (err, result) {\n        scriptsExited++;\n        if (scriptsExited == 10) {\n          pool.kill();\n          equal(10, result);\n          finished();\n        }\n      });\n      script.run({testGlobal: 10});\n    }\n  });\n\n  it('should run scripts on non blocking instances', function (finished) {\n    var pool = new Pool({numberOfInstances: 2});\n    var exited = false;\n    // Create blocking script.\n    var script = pool.createScript(\"\\\n        exports.main = function() {\\n\\\n          while(true);\\\n        }\\n\\\n      \"\n    );\n    script.run();\n\n    var scriptsExited = 0;\n    for (var i = 0; i < 10; ++i) {\n      var script2 = pool.createScript(\"\\\n          exports.main = function() {\\n\\\n            exit(10);\\n\\\n          }\\n\\\n        \"\n      );\n      script2.on('exit', function (err, result) {\n        scriptsExited++;\n        if (scriptsExited == 10) {\n          pool.kill();\n          equal(10, result);\n          exited = true;\n          finished();\n        }\n      });\n      script2.run();\n    }\n    setTimeout(function () {\n      if (!exited) {\n        equal(false, true);\n      }\n    }, 3000);\n  });\n\n  it('should not be created if there are zero or negative amount of specified instances', function (finished) {\n    var pool = null;\n    try {\n      pool = new Pool({numberOfInstances: 0});\n      equal(false, true);\n    } catch (error) {\n      notEqual(-1, error.indexOf(\"Can't create a pool with zero instances\"));\n      finished();\n    }\n  });\n});\n"
  },
  {
    "path": "test/sandcastle-test.js",
    "content": "var equal = require('assert').equal,\n  assert = require('assert'),\n  notEqual = require('assert').notEqual,\n  SandCastle = require('../lib').SandCastle,\n  Pool = require('../lib').Pool,\n  path = require('path');\n\ndescribe('SandCastle', function () {\n  it('should fire on(\"exit\") when a sandboxed script calls the exit method', function (finished) {\n    var sandcastle = new SandCastle();\n\n    var script = sandcastle.createScript(\"\\\n      exports.main = function() {\\\n        var result = 1 + 1;\\\n        exit({\\\n          results: [result]\\\n        });\\\n      }\\\n    \");\n\n    script.on('exit', function (err, result, methodName) {\n      sandcastle.kill();\n      equal(result.results[0], 2);\n      equal('main', methodName);\n      finished();\n    });\n\n    script.run();\n  });\n\n  it('should pass global variables to run()', function (finished) {\n    var sandcastle = new SandCastle();\n\n    var script = sandcastle.createScript(\"\\\n      exports.main = function() {\\\n        exit(foo);\\\n      }\\\n    \");\n\n    script.on('exit', function (err, result, methodName) {\n      sandcastle.kill();\n      equal('bar', result);\n      equal('main', methodName);\n      finished();\n    });\n\n    script.run({foo: 'bar'});\n  });\n\n  it('should run the specified function and pass global variables correctly', function (finished) {\n    var sandcastle = new SandCastle();\n\n    var script = sandcastle.createScript(\"\\\n      exports = {\\\n        foo: function () {\\\n          exit(foo);\\\n        }\\\n      };\\\n    \");\n\n    script.on('exit', function (err, result, methodName) {\n      sandcastle.kill();\n      equal('bar', result);\n      equal('foo', methodName);\n      finished();\n    });\n    script.run('foo', {foo: 'bar'});\n  });\n\n  it('should not allow require() to be called', function (finished) {\n    var sandcastle = new SandCastle();\n\n    var script = sandcastle.createScript(\"\\\n      exports.main = function() {\\\n        var net = require('net');\\\n      }\\\n    \");\n\n    script.on('exit', function (err, result) {\n      sandcastle.kill();\n      assert(err.message.match(/require is not defined/));\n      finished();\n    });\n\n    script.run();\n  });\n\n  it('should able to exit(null)', function (finished) {\n    var sandcastle = new SandCastle();\n\n    var script = sandcastle.createScript(\"\\\n      exports.main = function() {\\\n        exit(null);\\\n      }\\\n    \");\n\n    script.on('exit', function (err, result) {\n      sandcastle.kill();\n\t  equal(result,null);\n      finished();\n    });\n\n    script.run();\n  });\n\n  it('should provide an API', function (finished) {\n    var sandcastle = new SandCastle({\n      api: './examples/api.js'\n    });\n\n    var script = sandcastle.createScript(\"\\\n      exports.main = function() {\\\n        getFact(function(fact) {\\\n          exit(fact);\\\n        });\\\n      }\\\n    \");\n\n    script.on('exit', function (err, result) {\n      sandcastle.kill();\n      equal(result, 'The rain in spain falls mostly on the plain.');\n      finished();\n    });\n\n    script.run();\n  });\n\n  it('should allow API to be passed in as string', function(finished) {\n    var sandcastle = new SandCastle({\n      api: \"_ = require('lodash');\\\n        exports.api = {\\\n          map: function(values, cb) {\\\n            return _.map(values, cb);\\\n          }\\\n      }\"\n    });\n\n    var script = sandcastle.createScript(\"\\\n      exports.main = function() {\\\n        exit(map([{a: 1}, {a: 2}, {a: 3}], function(obj) {\\\n          return obj.a;\\\n        }))\\\n      }\\\n    \");\n\n    script.on('exit', function (err, result) {\n      sandcastle.kill();\n      equal(JSON.stringify(result), JSON.stringify([1, 2, 3]));\n      finished();\n    });\n\n    script.run();\n  });\n\n  it('should provide an API and a per-script API', function (finished) {\n    var sandcastle = new SandCastle({\n      api: './examples/api.js'\n    });\n\n    var script = sandcastle.createScript(\"\\\n      exports.main = function() {\\\n        callAdditional(function(fact) {\\\n          exit(fact);\\\n        });\\\n      }\\\n    \", {extraAPI: \"function anotherFunction(cb) { cb('The reign in spane falls mostly on the plain') }\" });\n\n    script.on('exit', function (err, result) {\n      sandcastle.kill();\n      equal(result, 'The reign in spane falls mostly on the plain');\n      finished();\n    });\n\n    script.run();\n  });\n\n  it('should timeout and respawn when looping script runs', function (finished) {\n    this.timeout(10000);\n\n    var sandcastle = new SandCastle({\n      api: './examples/api.js',\n      timeout: 2000\n    });\n\n    var loopingScript = sandcastle.createScript(\"\\\n      exports.main = function() {\\\n        while(true) {};\\\n      }\\\n    \");\n\n    var safeScript = sandcastle.createScript(\"\\\n      exports.main = function() {\\\n        exit('banana');\\\n      }\\\n    \");\n\n    safeScript.on('exit', function (err, result) {\n      sandcastle.kill();\n      equal(result, 'banana');\n      finished();\n    });\n\n    loopingScript.on('timeout', function (methodName) {\n      equal(methodName, 'main');\n      safeScript.run();\n    });\n\n    loopingScript.run();\n  });\n\n  it('should return a human readable stacktrace', function (finished) {\n    var sandcastle = new SandCastle();\n\n    var script = sandcastle.createScript(\"\\\n        exports.main = function() {\\n\\\n          var net = require('net');\\n\\\n        }\\n\\\n      \"\n    );\n\n    script.on('exit', function (err, result) {\n      sandcastle.kill();\n      equal(err.stack.indexOf('2:21') > -1, true);\n      finished();\n    });\n    script.run();\n  });\n\n  it('should enforce memory limit', function (finished) {\n    this.timeout(10000);\n\n    var sandcastle = new SandCastle({memoryLimitMB: 10});\n\n    var script = sandcastle.createScript(\"\\\n        exports.main = function() {\\n\\\n          var test = []; \\\n          for(var i = 0; i < 5000000; ++i) { \\\n            test[i] = 'a'; \\\n          } \\\n          exit(1); \\\n        }\\n\\\n      \"\n    );\n\n    script.on('exit', function (err, result) {\n      // Should not go here.\n      equal(false, true);\n    });\n\n    script.on('timeout', function (err, result) {\n      sandcastle.kill();\n      finished();\n    });\n    script.run();\n  });\n\n  it('sets cwd, when running scripts', function(finished) {\n    var cwd = process.cwd() + '/test';\n\n    var sandcastle = new SandCastle({\n      api: '../examples/api.js',\n      cwd: cwd\n    });\n\n    var script = sandcastle.createScript(\"\\\n      exports.main = function() {\\\n        exit({ cwd: cwd() });\\\n      }\\\n    \");\n\n    script.on('exit', function(err, result) {\n      equal(cwd, result.cwd);\n      sandcastle.kill();\n      finished();\n    });\n\n    script.run();\n  });\n\n  it('should allow api to see globals',function(finished){\n    var sandcastle = new SandCastle({\n      api: './examples/contextObjectApi.js'\n    });\n\n    var script = sandcastle.createScript(\"\\\n     exports.main = function() {\\n\\\n       var globalState = {};\\n\\\n       if(typeof state === \\\"undefined\\\"){\\n\\\n         globalState = 'none';\\n\\\n       }\\n\\\n       else{\\n\\\n         globalState = state;\\n\\\n       }\\n\\\n       exit({\\n\\\n         globalState:globalState,\\n\\\n         apiState:stateManager.getState()\\n\\\n       });\\n\\\n     }\\n\");\n\n    script.on('exit', function(err, result) {\n       equal(result.globalState, 'none');\n       equal(result.apiState.key, 'val');\n       sandcastle.kill();\n       finished();\n    });\n\n    script.run({state:{key:'val'}});\n  });\n\n  it('should correctly run the \"test\" task and and return the result', function (finished) {\n    var sandcastle = new SandCastle();\n\n    var script = sandcastle.createScript(\"\\\n      exports = {\\\n        onTestTask: function (data) {\\\n          if (data.count > 1) {\\\n            exit(data);\\\n          }\\\n          else {\\\n            runTask('test', data);\\\n          }\\\n        },\\\n        main: function() {\\\n          runTask('test', {count: 0});\\\n        }\\\n      }\\\n    \");\n\n    script.on('task', function (err, taskName, options, methodName, callback) {\n        options.count++;\n\n        equal(taskName, 'test');\n        equal(methodName, 'main');\n\n        return callback(options);\n    });\n\n    script.on('exit', function (err, result) {\n      equal(result.count, 2);\n      sandcastle.kill();\n      finished();\n    });\n\n    script.run();\n  });\n});\n"
  }
]