• Stars
    star
    500
  • Rank 88,178 (Top 2 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created about 9 years ago
  • Updated over 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

JSON extended with pure functions.

LJSON

LJSON is a drop-in replacement for JSON which also allows you to parse and stringify pure functions and their contents. There are good security reasons for functions to be out of the JSON specs, but most of those are only significant when you allow arbitrary, side-effective programs. With pure functions, one is able to interchange code while still being as safe as with regular JSON.

var LJSON = require("./LJSON.js");

// A random JS object with a pure function inside.
var person = {
    name : "John",
    mail : function(msg){ return { author  : "John", message : msg}; }
};

// If JSON was used, the `mail` field would be stripped from `personVal`.
var personStr = LJSON.stringify(person); 
var personVal = LJSON.parse(personStr);
var mail      = personVal.mail("hello"); // would crash with JSON

// But, since `mail` is pure, LJSON can deal with it correctly:
console.log("Serialized value : " + personStr);
console.log("Calling mail     : " + LJSON.stringify(mail));

Output:

Serialized value : {"name":"John","mail":(v0)=>({"author":"John","message":v0})}
Calling mail     : {"author":"John","message":"hello"}

See this and more examples on the Examples directory.

Also check Moon-lang, the spiritual successor of LJSON which includes primitive operations.

More info

Installing

npm install ljson

Or just download LJSON.js and parsinhora.js and import directly.

Other languages

Currently, there is a port to PHP kindly made by Kanti.

Why?

Other than convenience, there are times when you simply can't avoid running user code. For example, if a feature in your online game requires players to define scripts to control their ingame characters, you could implement it by receiving their code as strings, and using eval:

// client-side
script = ["function playerScript(player){",
    "if (player.targetInRange('poring'))",
        "player.castSpell('fire bolt',player.findTarget('poring'));",
"}"].join("\n");
server.send(script);

// server-side:
player.onSend("script",function(script){
    player.installScript(eval(script)); // what could go wrong
});

Except that is probably the worst idea ever. Trusting user defined code is a security-person's worst nightmare. Workarounds include sandboxes and defining your own safe DSL - but those solutions can be overkill. There is a simpler way: pure functions. Instead of starting with power to do anything (arbitrary functions) and struggling to control it, you start with no power at all (pure functions) and add only the right primitives to do what your app requires. The code above could be rewritten as:

// client-side
function playerScript($,player){
    return $("if", $("targetInRange", player, "poring"),
        $("castSpell", player, "fire bolt", $("findTarget", player, "poring")));
};
var script = LJSON.stringify(playerScript);
server.send(script);

// server-side:
player.onSend("script", function(script){
    player.installScript(LJSON.parseWithLib(safeLib, script)); // not so bad
});

Where the $ is an environment with the set of primitives your players are allowed to use, including things such as math operators, flow control and in-game commands. Of course, that lispy-like code isn't nearly as good looking as the former version, but is completely safe and pure. Functions defined that way can be stringified, communicated and parsed securely - just like JSON.

Using primitives

LJSON defines functions and function application only - no primitives such as numeric addition. So, for example, this is undefined behavior:

LJSON.stringify(function(x){ return x+1; });

Because the +1 bit isn't defined on LJSON. To actually do things with JS numbers, arrays, etc., you need to enable the proper primitives. You can do that either manually or by using LJSON's primitive decorators:

withLib(lib, fn)
withStdLib(fn)
parseWithLib(lib, source)
parseWithStdLib(source)

withLib uses the first argument of a pure function as a way to access the primitives defined on the lib object. For example:

var lib   = {triple:function(x){return x*3}};
nineTimes = LJSON.withLib(lib, function ($, x){
    return $("triple", $("triple",x));
});
console.log(nineTimes(9));

Here, $ can be understood as "apply function from environment". Since our environment only defines one function, triple, that's the only thing nineTimes can do. That is, it could multiply a number by 3, by 9, by 27, by 81, etc. - but it couldn't multiply a number by 2. That's how restricted your environment is! Of course, defining your own environment would be cumbersome if you just want to use JS's common functions. For that, there is LJSON.withStdLib, which enables an standard environment with most common (pure/safe) functions such as math operators and strings:

hypotenuse = function($,a,b){
    return $("sqrt",$("+",$("*",a,a),$("*",b,b)));
};
var hypotenuseStr = LJSON.stringify(hypotenuse);
var hypotenuseVal = LJSON.parseWithStdLib(hypotenuseStr);
console.log(hypotenuseVal(3,4)); // output: 5

Remember you have to enable a lib after stringifying, communicating/storing and parsing the function. It is the last step. After you call withStdLib, the function gains access to primitives outside of the LJSON specs, so LJSON.stringify will not work on it anymore.

Safety

The fact you have to explicitly provide primitives to LJSON functions is what gives you confidence they won't do any nasty thing such as stealing your password, mining bitcoins or launching missiles. LJSON functions can only do what you give them power to. You are still able to serialize side-effective functions, but the side effects will happen on the act of the serialization and get stripped from the serialized output.

function nastyPair(a,b){
    console.log("booom");
    return { 
        fst : a, 
        snd : (function nastyId(x){
            for (var i=0; i<3; ++i)
                console.log("mwahahhahha");
            return x;
        })(b)};
};
console.log(LJSON.stringify(nastyPair));

// output: 
// booom
// mwahahhahha
// mwahahhahha
// mwahahhahha
// (v0,v1)=>({fst:v0,snd:v1})

As a cool side effect of this, you can actually use JS primitives inside functions - as long as they can be eliminated at compile time. In other words, LJSON.stringify also works very well as a λ-calculator (due to JS engines speed):

console.log(LJSON.stringify(function(a){
    // Things known at compile time are evaluated.
    var arr = [];
    for (var i=0; i<10; ++i)
        arr.push(i*10);

    // Even inside functions.
    var foo = function(x){
        if (arr[5] < 10)
            var value = "I'm never returned";
        else
            var value = "I'm always returned";
        return value;
    };

    // Even λ-calculus expressions!
    var C3  = (f)=>(x)=>f(f(f(x)));
    var C27 = C3(C3); // church number exponentiation of 3^3

    return [
        arr,
        foo,
        C27];
}));

That outputs:

(v0)=>([
    [0,10,20,30,40,50,60,70,80,90],
    (v1)=>("I'm always returned"),
    (v2)=>((v3)=>(v2(v2(v2(v2(v2(v2(v2(v2(v2(v2(v2(v2(v2(v2(v2(v2(v2(v2(v2(v2(v2(v2(v2(v2(v2(v2(v2(v3)))))))))))))))))))))))))))))])

More Repositories

1

WebMonkeys

Massively parallel GPU programming on JavaScript, simple and clean.
JavaScript
1,163
star
2

Caramel

A modern syntax for the λ-calculus.
Haskell
405
star
3

PureState

The stupidest state management library that works.
JavaScript
309
star
4

forall

Expressive static types and invariant checks for JavaScript.
JavaScript
227
star
5

abstract-algorithm

Optimal evaluator of λ-calculus terms.
JavaScript
222
star
6

Cedille-Core

A minimal proof language.
JavaScript
193
star
7

optlam

An optimal function evaluator written in JavaScript.
JavaScript
115
star
8

Interaction-Type-Theory

Rust
108
star
9

calculus-of-constructions

Minimal, fast, robust implementation of the Calculus of Constructions on JavaScript.
JavaScript
94
star
10

Bitspeak

JavaScript
80
star
11

articles

Thoughts and stuff
JavaScript
65
star
12

UrnaCripto

Referendos criptograficamente incorruptíveis.
JavaScript
51
star
13

lrs

Linkable Ring Signatures on JavaScript and PureScript.
PureScript
46
star
14

lambda-calculus

A simple, clean and fast implementation of the λ-calculus on JavaScript.
JavaScript
44
star
15

heart

heart
JavaScript
41
star
16

ultimate-calculus

TypeScript
36
star
17

absal-rs

Rust
36
star
18

HOC

C
32
star
19

nano-json-stream-parser

A complete, pure JavaScript, streamed JSON parser in less than 1kb.
JavaScript
29
star
20

servify

Microservices in the simplest way conceivable.
JavaScript
28
star
21

optimul

Multiplication on optimal λ-calculus reducers
JavaScript
22
star
22

parallel_lambda_computer_tests

learning cuda
Cuda
18
star
23

nano-ipfs-store

Lightweight library to store and get data to/from IPFS
JavaScript
14
star
24

formality-agda-lib-legacy

Agda libraries relevant to Moonad
Agda
14
star
25

taemoba

13
star
26

unknown_halting_status

Small programs with unknown halting status.
JavaScript
12
star
27

lsign

Quantum-proof, 768-bit signatures for 1-bit messages
JavaScript
11
star
28

reasoning_evals

my reasoning evals
JavaScript
9
star
29

Elementary-Affine-Net-legacy

JavaScript
8
star
30

OpenLegends

An open-source MOBA in Rust
6
star
31

ethereum-offline-signer

Signs an Ethereum transaction from the command line.
JavaScript
6
star
32

coc-with-math-prims

JavaScript
5
star
33

idris-mergesort-benchmark

Benchmark of the new Idris JS backend
JavaScript
5
star
34

uwuchat2_demo

UwUChat2 demo game
TypeScript
5
star
35

LPU

JavaScript
4
star
36

Vote

3
star
37

nano-persistent-memoizer

Caches a function permanently on browser and node.
JavaScript
3
star
38

nano-sha256

Use native Sha256 on both browser and Node.js
JavaScript
3
star
39

ReflexScreenWidget

A widget for Haskell-Reflex that renders a dynamic image to a Canvas in realtime.
Haskell
3
star
40

OSX

Vim script
3
star
41

EthFP

3
star
42

VictorTaelin

3
star
43

ethereum-rpc

JavaScript
2
star
44

ethereum-publisher-dapp

JavaScript
2
star
45

shared-state-machine

JavaScript
2
star
46

Trabalho-IC-UFRJ-2

Python
2
star
47

NeoTaelin

2
star
48

eth-web-tools

Some web Ethereum tools that MyEtherWallet currently lacks
JavaScript
2
star
49

hvm2

Cuda
2
star
50

symmetric-interaction-calculus-benchmarks

SIC benchmarks
JavaScript
2
star
51

talks

C
2
star
52

gpt

2
star
53

agbook

AGDA
Agda
2
star
54

Kind2

Kind refactor based on HVM
2
star
55

kind-react-component

Renders a Kind app as a React component
1
star
56

PongFromScratch

A simple tutorial on how to create a ping-pong game from scratch
1
star
57

tsbook

TypeScript
1
star
58

sketch_bros

Super Sketch Bros!
JavaScript
1
star
59

StupidMinimalistHash

C
1
star
60

MaiaVictor.github.io

HTML
1
star
61

PotS

JavaScript
1
star
62

LamBolt

The ultimate compile target for functional languages
1
star
63

form-login

Um formulário de Login feito com HTML e CSS usando transições
CSS
1
star
64

who-loves-voxels

JavaScript
1
star
65

cuda_rewrite_tests

learning cuda
Cuda
1
star
66

luna-lang-old-abandoned-repo

Typed version of Moon-lang
JavaScript
1
star
67

posts

1
star
68

FPL

A collection of functional JavaScript modules.
JavaScript
1
star
69

PassRhyme

JavaScript
1
star
70

something_calculus

1
star
71

moon-bignum

Minimalistic bignum library compiled from Moon-lang.
JavaScript
1
star
72

see

See inside JS functions
JavaScript
1
star
73

Trabalho-IC-UFRJ

JavaScript
1
star
74

optimal_evaluation_examples

optimal evaluation examples (DUP nodes, SUP nodes)
Haskell
1
star
75

inferno-hello-world-component

JavaScript
1
star
76

inet

JavaScript
1
star