Adder
Executing untrusted code with ease.
Install / Use
/learn @RonenNess/AdderREADME

AdderScript
Executing untrusted code with ease.
What is it
Adder is a lightweight python-like language, implemented on top of JavaScript and designed to be safe to execute untrusted code.
Why?
The main purpose of Adder is to let you execute untrusted code on other users's browsers and even on your Node.js server, without worrying about security complications.
Adder will not let the untrusted code access anything you don't want it to access, will not allow it to get stuck or hog resources, and will make sure it can't do any harm or go outside its boundaries.
The main reason Adder is secured is that no JavaScript code is ever executed using plain eval(). Instead, everything is parsed and interpreted by the Adder interpreter, that is built and designed to be limited and safe.
Advantages
Here are the key features of Adder:
- Beautiful Pythonic syntax - if you know Python, you know Adder.
- Secured by design (Adder is designed to run untrusted code).
- Works on both Node.js and Browsers.
- No need for any sub-processes.
- Simple & accessible interface.
- Easy to extend, and easy to remove builtins and limit.
- Agnostic to JavaScript changes and versions.
- Easy to limit memory usage, commands per run, execution time, etc..
- Caching and Optimizations makes it pretty fast for multiple executions.
Platforms
Adder works and heavily tested on the following browsers / platforms:
- Chrome 53
- IE Edge
- FireFox 45
- Opera 40
- Node.js 4.1.1

Install
There are several ways to install Adder:
Via npm
npm install adder-script
Via bower
bower install adder-script
Via git (clone)
git clone https://github.com/RonenNess/adder.git
Or you can download from the GitHub repository.
Building The Code
To build the distributed version for client side, run the command build.bat.
It uses browserify and uglifyjs, so be sure to install them first.
Tests & Examples
Tests
To run Adder tests, you can open the html file tests/test.html in the browser of your choice.
To test in Node.js, run the following command (requires Node.js and qunit-cli installed):
qunit-cli tests/test.js
Performance Tests
To run performance tests, open the html file tests/performance.html in the browser of your choice. To test performance in Node.js, execute file tests/performance-node.js in Node.
Note that results may vary from run to run, so its recommended to execute several times and do an average.
Interactive Shell
To get an interactive shell and play with the language, you can open examples/shell.html in the browser of your choice.
Sandbox
To get a rich Adder sandbox with code examples and minimal editor, you can open examples/sandbox.html in the browser of your choice.
Performance
In overall, Adder appears to be 3-5 times slower than executing plain JavaScript, on multiple executions. On FireFox it appears to be much faster, due to caching of expressions.
The following is a summary of performance tests I conducted on multiple browsers (with windows 8). In bars below less is better:

These tests execute the same logic with Adder and JavaScript couple thousands of times, and measure the time it took to execute each code.
Please note:
- The tests above don't include compile time (Adder scripts are compiled prior the tests).
- Adder programs that execute multiple times have internal caching which makes them faster. If your project run each Adder program only once, performance would be slightly worse.
For more info check out tests/performance.html.
Executing Adder - Host application side
This part of the docs explain how to setup and execute Adder from the host application side, eg the client JavaScript or your Node.js server.
Later in these docs we'll learn the language itself and how to write Adder scripts.
Quick Example
Before diving into the APIs, lets start with a simple example:
// init Adder environment (connect output to alerts)
AdderScript.init({
outputFunc: function(text) {alert("output from script: " + text);},
});
// create a simple script and compile it
compiledCode = AdderScript.compile('print("Hello World!")');
// spawn a program and execute it
// the result will be an alert with the text "Hello World!".
var program = AdderScript.newProgram(compiledCode);
program.execute();
Pretty simple right? Now lets dive in a little deeper.
Init Environment
To run Adder scripts you first need to init environment:
// if you don't provide any params output will go to console.log and default flags will apply
AdderScript.init();
Compile Code
Once the environment is ready, you can compile Adder codes using the compile function:
var compiled = AdderScript.compile(someCodeString);
Save / Load pre-compiled code
If you want to save the compiled code for later usage, you can simply JSON.stringify() it into a file:
// require fs
var fs = require('fs');
// save compiled code:
fs.writeFile(filename, JSON.stringify(compiledCode), function(err) {
// handle errors...
});
// load compiled code you previously saved
fs.readFile(filename, 'utf8', function(err, data) {
if (err) // handle errors...
compiledCode = JSON.parse(data);
});
Create & Execute Programs
An Adder Program can be think of as a process executing a single Adder script one or more times.
However, the Adder program is not a real process but an object living on the same memory space as the host application.
To spawn a new program from a compiled code, use newProgram():
var program = AdderScript.newProgram(compiledCode);
The program will now live in memory and you can execute it as many times as needed and access its internal memory and variables.
Executing the same program multiple times is much faster than spawning a new program every time, due to caching and internal optimizations. In addition, global scope variables will stay alive between different executions of the same program.
To execute the program code once, use execute:
program.execute();
If you want to clear your program's context (eg remove all user defined variables from global scope), use resetContext():
program.resetContext();
Get values and execution errors
You can easily access the last evaluated result and get it as a native JavaScript object, using getLastValue():
var lastVal = program.getLastValue();
In addition, you can read any variable in the program's global scope using getGlobalVar():
// get variable from global scope as native javascript object
var value = program.getGlobalVar("var_name");
Or, you can set any variable in the program's global scope using setGlobalVar():
// set variable in program global scope
program.setGlobalVar("var_name", value, isReadonly);
In addition, you can check if any error occurred during the last execution, using getLastError():
var lastError = program.getLastError();
if (lastError) {
console.log(lastError.message);
}
You can see all Adder error types in object AdderScript.Errors, or in file errors.js.
Advanced init settings
When init Adder environment you can provide a dictionary with the following settings:
AdderScript.init({
flags: {}, // different compiler / interpreter flags you can set (explained later).
modules: ["ALL"], // which modules to load. ['ALL'] will load all built-in modules.
outputFunc: printOutput, // function to handle scripts output, when print() is called.
showDebugConsole: true, // if true, Adder will dump some extra debug data to console.
});
flags
The following are all the flags you can set when you init Adder environment (as the 'flags' option):
var flags = {
stackLimit: 256, // Stack depth limit. If exceeded will throw 'StackOverflow' exception.
maxStatementsPerRun: 2048, // Maximum statements that can be executed in a single run. If exceeded will throw 'ExceededStatementsLimit' exception.
maxStringLen: 5000, // Maximum allowed string lengths. If exceeded will throw 'ExceedMemoryLimit' exception.
maxContainersLen: 1000, // Maximum values allowed in lists, sets and dictionaries. If exceeded will throw 'ExceedMemoryLimit' exception.
maxVarsInScope: 100, // Limit number of variables allowed per scope. If exceeded will throw 'ExceedMemoryLimit' exception.
executionTimeLimit: 1000, // Time limit for a single execution (in milliseconds). If exceeded will throw 'ExceededTimeLimit' exception.
memoryAllocationLimit: 10000, // Memory limit, very roughly estimated, in bytes (per execution). If exceeded will throw 'ExceedMemoryLimit' exception.
removeBuiltins: [], // An optional list of builtin function and const names you want to remove from the language.
throwErrors: false, // If true, will throw exceptions from Adder execution if occur. If false, you need to check errors with getLastError().
}
modules
Modules are objects with functions and consts you can access from Adder scripts. For example, there's the built-in Math module that provide all the Math-related functionality and consts.
You can choose which modules are included in your environment to have fine control over which APIs Adder scripts can access.
Note that you cannot import m
