SkillAgentSearch skills...

Adder

Executing untrusted code with ease.

Install / Use

/learn @RonenNess/Adder
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

AdderScript

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

platforms

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:

Performance table

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

View on GitHub
GitHub Stars48
CategoryDevelopment
Updated12mo ago
Forks4

Languages

JavaScript

Security Score

87/100

Audited on Apr 4, 2025

No findings