jail

package
v0.0.0-...-084c4e9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 16, 2018 License: MPL-2.0 Imports: 20 Imported by: 0

README

jail GoDoc

jail - jailed environment for executing JS code.

Download:

go get github.com/status-im/status-go/jail

jail - jailed environment for executing JS code.

Package jail implements "jailed" environment for executing arbitrary JavaScript code using Otto JS interpreter (https://github.com/robertkrimen/otto).

Jail create multiple Cells, one cell per status client chat. Each cell runs own Otto virtual machine and lives forever, but that may change in the future.

+----------------------------------------------+
|                     Jail                     |
+----------------------------------------------+
+---------+ +---------+ +---------+  +---------+
|  Cell   | |  Cell   | |  Cell   |  |  Cell   |
|ChatID 1 | |ChatID 2 | |ChatID 3 |  |ChatID N |
|+-------+| |+-------+| |+-------+|  |+-------+|
||Otto VM|| ||Otto VM|| ||Otto VM||  ||Otto VM||
|+-------+| |+-------+| |+-------+|  |+-------+|
|| Loop  || || Loop  || || Loop  ||  || Loop  ||
++-------++ ++-------++ ++-------++  ++-------++

Cells

Each Cell object embeds *VM from 'jail/vm' for concurrency safe wrapper around *otto.VM functions. This is important when dealing with setTimeout and Fetch API functions (see below).

Get and Set

(*VM).Get/Set functions provide transparent and concurrently safe wrappers for Otto VM Get and Set functions respectively. See Otto documentation for usage examples: https://godoc.org/github.com/robertkrimen/otto

Call and Run

(*VM).Call/Run functions allows executing arbitrary JS in the cell. They're also wrappers around Otto VM functions of the same name. Run accepts raw JS strings for execution while Call takes a JS function name (defined in VM) and parameters.

Timeouts and intervals support

Default Otto VM interpreter doesn't support setTimeout() / setInterval() JS functions, because they're not part of ECMA-262 spec, but properties of the window object in browser.

We add support for them using own implementation of Event Loop, heavily based on ottoext package. See loop/fetch/promise packages under jail/internal/.

Each cell starts a new loop in a separate goroutine, registers functions for setTimeout / setInterval calls and associate them with this loop. All JS code executed as callback to setTimeout/setInterval will be handled by this loop.

For example, following code:

cell.Run(`setTimeout(function(){ value = "42" }, 2000);`)

will execute setTimeout and return immediately, but callback function will be executed after 2 seconds in the loop that was started upon current cell.

In order to capture response one may use following approach:

err = cell.Set("__captureResponse", func(val string) otto.Value {
	fmt.Println("Captured response from callback:", val)
	return otto.UndefinedValue()
})
cell.Run(`setTimeout(function(){ __captureResponse("OK") }, 2000);`)

Fetch support

Fetch API is implemented in a similar way using the same loop. When Cell is created, corresponding handlers are registered within VM and associated event loop.

Due to asynchronous nature of Fetch API, the following code will return immediately:

cell.Run(`fetch('http://example.com/').then(function(data) { ... })`)

and callback function in a promise will be executed in a event loop in the background. Thus, it's user responsibility to register a corresponding callback function before:

cell.Set("__captureSuccess", func(res otto.Value) { ... })

cell.Run(`fetch('http://example.com').then(function(r) {
	return r.text()
}).then(function(data) {
	// user code
	__captureSuccess(data)
}))

Automatically generated by autoreadme on 2018.02.08

Documentation

Overview

Package jail is a generated GoMock package.

Package jail - jailed environment for executing JS code.

Package jail implements "jailed" environment for executing arbitrary JavaScript code using Otto JS interpreter (https://github.com/robertkrimen/otto).

Jail create multiple Cells, one cell per status client chat. Each cell runs own Otto virtual machine and lives forever, but that may change in the future.

+----------------------------------------------+
|                     Jail                     |
+----------------------------------------------+
+---------+ +---------+ +---------+  +---------+
|  Cell   | |  Cell   | |  Cell   |  |  Cell   |
|ChatID 1 | |ChatID 2 | |ChatID 3 |  |ChatID N |
|+-------+| |+-------+| |+-------+|  |+-------+|
||Otto VM|| ||Otto VM|| ||Otto VM||  ||Otto VM||
|+-------+| |+-------+| |+-------+|  |+-------+|
|| Loop  || || Loop  || || Loop  ||  || Loop  ||
++-------++ ++-------++ ++-------++  ++-------++

## Cells Each Cell object embeds *VM from 'jail/vm' for concurrency safe wrapper around *otto.VM functions. This is important when dealing with setTimeout and Fetch API functions (see below).

## Get and Set (*VM).Get/Set functions provide transparent and concurrently safe wrappers for Otto VM Get and Set functions respectively. See Otto documentation for usage examples: https://godoc.org/github.com/robertkrimen/otto

## Call and Run (*VM).Call/Run functions allows executing arbitrary JS in the cell. They're also wrappers around Otto VM functions of the same name. `Run` accepts raw JS strings for execution while `Call` takes a JS function name (defined in VM) and parameters.

## Timeouts and intervals support Default Otto VM interpreter doesn't support setTimeout() / setInterval() JS functions, because they're not part of ECMA-262 spec, but properties of the window object in browser.

We add support for them using own implementation of Event Loop, heavily based on [ottoext package](https://github.com/deoxxa/ottoext). See loop/fetch/promise packages under [jail/internal/](https://github.com/status-im/status-go/tree/develop/jail/internal).

Each cell starts a new loop in a separate goroutine, registers functions for setTimeout / setInterval calls and associate them with this loop. All JS code executed as callback to setTimeout/setInterval will be handled by this loop.

For example, following code:

cell.Run(`setTimeout(function(){ value = "42" }, 2000);`)

will execute setTimeout and return immediately, but callback function will be executed after 2 seconds in the loop that was started upon current cell.

In order to capture response one may use following approach:

err = cell.Set("__captureResponse", func(val string) otto.Value {
	fmt.Println("Captured response from callback:", val)
	return otto.UndefinedValue()
})
cell.Run(`setTimeout(function(){ __captureResponse("OK") }, 2000);`)

## Fetch support

Fetch API is implemented in a similar way using the same loop. When Cell is created, corresponding handlers are registered within VM and associated event loop.

Due to asynchronous nature of Fetch API, the following code will return immediately:

cell.Run(`fetch('http://example.com/').then(function(data) { ... })`)

and callback function in a promise will be executed in a event loop in the background. Thus, it's user responsibility to register a corresponding callback function before:

cell.Set("__captureSuccess", func(res otto.Value) { ... })

cell.Run(`fetch('http://example.com').then(function(r) {
	return r.text()
}).then(function(data) {
	// user code
	__captureSuccess(data)
}))

Index

Constants

View Source
const (

	// EmptyResponse is returned when cell is successfully created and initialized
	// but no additional JS was provided to the initialization method.
	EmptyResponse = `{"result": ""}`
)

Variables

View Source
var (
	// ErrNoRPCClient is returned when an RPC client is required but it's nil.
	ErrNoRPCClient = errors.New("RPC client is not available")
)

Functions

This section is empty.

Types

type Cell

type Cell struct {
	// contains filtered or unexported fields
}

Cell represents a single jail cell, which is basically a JavaScript VM.

func NewCell

func NewCell(id string) (*Cell, error)

NewCell encapsulates what we need to create a new jailCell from the provided vm and eventloop instance.

func (*Cell) Call

func (c *Cell) Call(item string, this interface{}, args ...interface{}) (JSValue, error)

Call calls Call on the underlying JavaScript VM and returns a wrapper around the otto.Value.

func (*Cell) CallAsync

func (c *Cell) CallAsync(fn otto.Value, args ...interface{}) error

CallAsync puts otto's function with given args into event queue loop and schedules for immediate execution. Intended to be used by any cell user that want's to run async call, like callback.

func (*Cell) Get

func (c *Cell) Get(key string) (JSValue, error)

Get calls Get on the underlying JavaScript VM and returns a wrapper around the otto.Value.

func (*Cell) GetObjectValue

func (c *Cell) GetObjectValue(v otto.Value, name string) (JSValue, error)

GetObjectValue calls GetObjectValue on the underlying JavaScript VM and returns a wrapper around the otto.Value.

func (*Cell) Run

func (c *Cell) Run(src interface{}) (JSValue, error)

Run calls Run on the underlying JavaScript VM and returns a wrapper around the otto.Value.

func (*Cell) Set

func (c *Cell) Set(key string, val interface{}) error

Set calls Set on the underlying JavaScript VM.

func (*Cell) Stop

func (c *Cell) Stop() error

Stop halts event loop associated with cell.

type JSCell

type JSCell interface {
	// Set a value inside VM.
	Set(string, interface{}) error
	// Get a value from VM.
	Get(string) (JSValue, error)
	// Run an arbitrary JS code. Input maybe string or otto.Script.
	Run(interface{}) (JSValue, error)
	// Call an arbitrary JS function by name and args.
	Call(item string, this interface{}, args ...interface{}) (JSValue, error)
	// Stop stops background execution of cell.
	Stop() error
}

JSCell represents single jail cell, which is basically a JavaScript VM. It's designed to be a transparent wrapper around otto.VM's methods.

type JSValue

type JSValue struct {
	// contains filtered or unexported fields
}

JSValue is a wrapper around an otto.Value.

func (*JSValue) Value

func (v *JSValue) Value() otto.Value

Value returns the underlying otto.Value from a JSValue. This value IS NOT THREADSAFE.

type Jail

type Jail struct {
	// contains filtered or unexported fields
}

Jail manages multiple JavaScript execution contexts (JavaScript VMs) called cells. Each cell is a separate VM with web3.js set up.

As rpc.Client might not be available during Jail initialization, a provider function is used.

func New

func New(provider RPCClientProvider) *Jail

New returns a new Jail.

func NewWithBaseJS

func NewWithBaseJS(provider RPCClientProvider, code string) *Jail

NewWithBaseJS returns a new Jail with base JS configured.

func (*Jail) Call

func (j *Jail) Call(chatID, commandPath, args string) string

Call executes the `call` function within a cell with chatID. Returns a string being a valid JS code. In case of a successful result, it's {"result": any}. In case of an error: {"error": "some error"}.

Call calls commands from `_status_catalog`. commandPath is an array of properties to retrieve a function. For instance:

`["prop1", "prop2"]` is translated to `_status_catalog["prop1"]["prop2"]`.

func (*Jail) Cell

func (j *Jail) Cell(chatID string) (JSCell, error)

Cell returns a cell by chatID. If it does not exist, error is returned. Required by the Backend.

func (*Jail) CreateAndInitCell

func (j *Jail) CreateAndInitCell(chatID string, code ...string) string

CreateAndInitCell creates and initializes new Cell.

func (*Jail) CreateCell

func (j *Jail) CreateCell(chatID string) (JSCell, error)

CreateCell creates a new cell. It returns an error if a cell with a given ID already exists.

func (*Jail) Execute

func (j *Jail) Execute(chatID, code string) string

Execute allows to run arbitrary JS code within a cell.

func (*Jail) Parse

func (j *Jail) Parse(chatID, code string) string

Parse creates a new jail cell context, with the given chatID as identifier. New context executes provided JavaScript code, right after the initialization. DEPRECATED in favour of CreateAndInitCell.

func (*Jail) RPCClient

func (j *Jail) RPCClient() *rpc.Client

RPCClient returns an rpc.Client.

func (*Jail) SetBaseJS

func (j *Jail) SetBaseJS(js string)

SetBaseJS sets initial JavaScript code loaded to each new cell.

func (*Jail) Stop

func (j *Jail) Stop()

Stop stops jail and all assosiacted cells.

type Manager

type Manager interface {
	// Call executes given JavaScript function w/i a jail cell context identified by the chatID.
	Call(chatID, this, args string) string

	// CreateCell creates a new jail cell.
	CreateCell(chatID string) (JSCell, error)

	// Parse creates a new jail cell context, with the given chatID as identifier.
	// New context executes provided JavaScript code, right after the initialization.
	// DEPRECATED in favour of CreateAndInitCell.
	Parse(chatID, js string) string

	// CreateAndInitCell creates a new jail cell and initialize it
	// with web3 and other handlers.
	CreateAndInitCell(chatID string, code ...string) string

	// Cell returns an existing instance of JSCell.
	Cell(chatID string) (JSCell, error)

	// Execute allows to run arbitrary JS code within a cell.
	Execute(chatID, code string) string

	// SetBaseJS allows to setup initial JavaScript to be loaded on each jail.CreateAndInitCell().
	SetBaseJS(js string)

	// Stop stops all background activity of jail
	Stop()
}

Manager defines methods for managing jailed environments

type MockJSCell

type MockJSCell struct {
	// contains filtered or unexported fields
}

MockJSCell is a mock of JSCell interface

func NewMockJSCell

func NewMockJSCell(ctrl *gomock.Controller) *MockJSCell

NewMockJSCell creates a new mock instance

func (*MockJSCell) Call

func (m *MockJSCell) Call(item string, this interface{}, args ...interface{}) (JSValue, error)

Call mocks base method

func (*MockJSCell) EXPECT

func (m *MockJSCell) EXPECT() *MockJSCellMockRecorder

EXPECT returns an object that allows the caller to indicate expected use

func (*MockJSCell) Get

func (m *MockJSCell) Get(arg0 string) (JSValue, error)

Get mocks base method

func (*MockJSCell) Run

func (m *MockJSCell) Run(arg0 interface{}) (JSValue, error)

Run mocks base method

func (*MockJSCell) Set

func (m *MockJSCell) Set(arg0 string, arg1 interface{}) error

Set mocks base method

func (*MockJSCell) Stop

func (m *MockJSCell) Stop() error

Stop mocks base method

type MockJSCellMockRecorder

type MockJSCellMockRecorder struct {
	// contains filtered or unexported fields
}

MockJSCellMockRecorder is the mock recorder for MockJSCell

func (*MockJSCellMockRecorder) Call

func (mr *MockJSCellMockRecorder) Call(item, this interface{}, args ...interface{}) *gomock.Call

Call indicates an expected call of Call

func (*MockJSCellMockRecorder) Get

func (mr *MockJSCellMockRecorder) Get(arg0 interface{}) *gomock.Call

Get indicates an expected call of Get

func (*MockJSCellMockRecorder) Run

func (mr *MockJSCellMockRecorder) Run(arg0 interface{}) *gomock.Call

Run indicates an expected call of Run

func (*MockJSCellMockRecorder) Set

func (mr *MockJSCellMockRecorder) Set(arg0, arg1 interface{}) *gomock.Call

Set indicates an expected call of Set

func (*MockJSCellMockRecorder) Stop

func (mr *MockJSCellMockRecorder) Stop() *gomock.Call

Stop indicates an expected call of Stop

type MockManager

type MockManager struct {
	// contains filtered or unexported fields
}

MockManager is a mock of Manager interface

func NewMockManager

func NewMockManager(ctrl *gomock.Controller) *MockManager

NewMockManager creates a new mock instance

func (*MockManager) Call

func (m *MockManager) Call(chatID, this, args string) string

Call mocks base method

func (*MockManager) Cell

func (m *MockManager) Cell(chatID string) (JSCell, error)

Cell mocks base method

func (*MockManager) CreateAndInitCell

func (m *MockManager) CreateAndInitCell(chatID string, code ...string) string

CreateAndInitCell mocks base method

func (*MockManager) CreateCell

func (m *MockManager) CreateCell(chatID string) (JSCell, error)

CreateCell mocks base method

func (*MockManager) EXPECT

func (m *MockManager) EXPECT() *MockManagerMockRecorder

EXPECT returns an object that allows the caller to indicate expected use

func (*MockManager) Execute

func (m *MockManager) Execute(chatID, code string) string

Execute mocks base method

func (*MockManager) Parse

func (m *MockManager) Parse(chatID, js string) string

Parse mocks base method

func (*MockManager) SetBaseJS

func (m *MockManager) SetBaseJS(js string)

SetBaseJS mocks base method

func (*MockManager) Stop

func (m *MockManager) Stop()

Stop mocks base method

type MockManagerMockRecorder

type MockManagerMockRecorder struct {
	// contains filtered or unexported fields
}

MockManagerMockRecorder is the mock recorder for MockManager

func (*MockManagerMockRecorder) Call

func (mr *MockManagerMockRecorder) Call(chatID, this, args interface{}) *gomock.Call

Call indicates an expected call of Call

func (*MockManagerMockRecorder) Cell

func (mr *MockManagerMockRecorder) Cell(chatID interface{}) *gomock.Call

Cell indicates an expected call of Cell

func (*MockManagerMockRecorder) CreateAndInitCell

func (mr *MockManagerMockRecorder) CreateAndInitCell(chatID interface{}, code ...interface{}) *gomock.Call

CreateAndInitCell indicates an expected call of CreateAndInitCell

func (*MockManagerMockRecorder) CreateCell

func (mr *MockManagerMockRecorder) CreateCell(chatID interface{}) *gomock.Call

CreateCell indicates an expected call of CreateCell

func (*MockManagerMockRecorder) Execute

func (mr *MockManagerMockRecorder) Execute(chatID, code interface{}) *gomock.Call

Execute indicates an expected call of Execute

func (*MockManagerMockRecorder) Parse

func (mr *MockManagerMockRecorder) Parse(chatID, js interface{}) *gomock.Call

Parse indicates an expected call of Parse

func (*MockManagerMockRecorder) SetBaseJS

func (mr *MockManagerMockRecorder) SetBaseJS(js interface{}) *gomock.Call

SetBaseJS indicates an expected call of SetBaseJS

func (*MockManagerMockRecorder) Stop

func (mr *MockManagerMockRecorder) Stop() *gomock.Call

Stop indicates an expected call of Stop

type RPCClientProvider

type RPCClientProvider interface {
	RPCClient() *rpc.Client
}

RPCClientProvider is an interface that provides a way to obtain an rpc.Client.

Directories

Path Synopsis
Package ottoext contains some extensions for the otto JavaScript interpreter.
Package ottoext contains some extensions for the otto JavaScript interpreter.
vm

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL