22
33Like ` JSON.stringify ` , but handles
44
5- - cyclical references (` obj.self = obj ` )
6- - repeated references (` [value, value] ` )
7- - ` undefined ` , ` Infinity ` , ` NaN ` , ` -0 `
8- - regular expressions
9- - dates
10- - ` Map ` and ` Set `
11- - ` BigInt `
5+ - cyclical references (` obj.self = obj ` )
6+ - repeated references (` [value, value] ` )
7+ - ` undefined ` , ` Infinity ` , ` NaN ` , ` -0 `
8+ - regular expressions
9+ - dates
10+ - ` Map ` and ` Set `
11+ - ` BigInt `
1212
1313Try it out [ here] ( https://svelte.dev/repl/138d70def7a748ce9eda736ef1c71239?version=3.49.0 ) .
1414
1515## Goals:
1616
17- - Performance
18- - Security (see [ XSS mitigation] ( #xss-mitigation ) )
19- - Compact output
17+ - Performance
18+ - Security (see [ XSS mitigation] ( #xss-mitigation ) )
19+ - Compact output
2020
2121## Non-goals:
2222
23- - Human-readable output
24- - Stringifying functions or non-POJOs
23+ - Human-readable output
24+ - Stringifying functions or non-POJOs
2525
2626## Usage
2727
2828``` js
29- import { devalue } from ' devalue' ;
29+ import { devalue } from " devalue" ;
3030
3131let obj = { a: 1 , b: 2 };
3232obj .c = 3 ;
@@ -35,6 +35,9 @@ devalue(obj); // '{a:1,b:2,c:3}'
3535
3636obj .self = obj;
3737devalue (obj); // '(function(a){a.a=1;a.b=2;a.c=3;a.self=a;return a}({}))'
38+
39+ // Deserialize into new object
40+ let newObject = (0 , eval)(" (" + devalue (obj) + " )" );
3841```
3942
4043## Error handling
@@ -43,16 +46,16 @@ If `devalue` encounters a function or a non-POJO, it will throw an error. You ca
4346
4447``` js
4548try {
46- const map = new Map ();
47- map .set (' key' , function invalid () {});
48-
49- devalue ({
50- object: {
51- array: [map]
52- }
53- })
49+ const map = new Map ();
50+ map .set (" key" , function invalid () {});
51+
52+ devalue ({
53+ object: {
54+ array: [map],
55+ },
56+ });
5457} catch (e) {
55- console .log (e .path ); // '.object.array[0].get("key")'
58+ console .log (e .path ); // '.object.array[0].get("key")'
5659}
5760```
5861
@@ -62,7 +65,7 @@ Say you're server-rendering a page and want to serialize some state, which could
6265
6366``` js
6467const state = {
65- userinput: ` </script><script src='https://evil.com/mwahaha.js'>`
68+ userinput: ` </script><script src='https://evil.com/mwahaha.js'>` ,
6669};
6770
6871const template = `
@@ -76,11 +79,11 @@ Which would result in this:
7679
7780``` html
7881<script >
79- // NEVER DO THIS
80- var preloaded = {" userinput" : "
82+ // NEVER DO THIS
83+ var preloaded = {" userinput" : "
8184</script>
8285<script src=" https: // evil.com/mwahaha.js">
83- " };
86+ " };
8487</script>
8588```
8689
@@ -95,17 +98,17 @@ const template = `
9598
9699```html
97100<script>
98- var preloaded = {
99- userinput:
100- " \\u003C\\u002Fscript\\u003E\\u003Cscript src= ' https:\\ u002F\\ u002Fevil.com\\ u002Fmwahaha.js' \\u003E"
101- };
101+ var preloaded = {
102+ userinput:
103+ " \\u003C\\u002Fscript\\u003E\\u003Cscript src= ' https:\\ u002F\\ u002Fevil.com\\ u002Fmwahaha.js' \\u003E" ,
104+ };
102105</script>
103106```
104107
105108This, along with the fact that `devalue` bails on functions and non-POJOs, stops attackers from executing arbitrary code. Strings generated by `devalue` can be safely deserialized with `eval` or `new Function`:
106109
107110```js
108- const value = (0, eval)('(' + str + ')' );
111+ const value = (0, eval)(" ( " + str + " ) " );
109112```
110113
111114## Other security considerations
@@ -116,22 +119,22 @@ When using `eval`, ensure that you call it _indirectly_ so that the evaluated co
116119
117120```js
118121{
119- const sensitiveData = ' Setec Astronomy' ;
120- eval(' sendToEvilServer(sensitiveData)' ); // pwned :(
121- (0, eval)(' sendToEvilServer(sensitiveData)' ); // nice try, evildoer!
122+ const sensitiveData = " Setec Astronomy" ;
123+ eval(" sendToEvilServer (sensitiveData)" ); // pwned :(
124+ (0, eval)(" sendToEvilServer (sensitiveData)" ); // nice try, evildoer!
122125}
123126```
124127
125128Using `new Function(code)` is akin to using indirect eval.
126129
127130## See also
128131
129- - [lave](https://github.com/jed/lave) by Jed Schmidt
130- - [arson](https://github.com/benjamn/arson) by Ben Newman
131- - [tosource](https://github.com/marcello3d/node-tosource) by Marcello Bastéa-Forte
132- - [serialize-javascript](https://github.com/yahoo/serialize-javascript) by Eric Ferraiuolo
133- - [jsesc](https://github.com/mathiasbynens/jsesc) by Mathias Bynens
134- - [superjson](https://github.com/blitz-js/superjson) by Blitz
132+ - [lave](https://github.com/jed/lave) by Jed Schmidt
133+ - [arson](https://github.com/benjamn/arson) by Ben Newman
134+ - [tosource](https://github.com/marcello3d/node-tosource) by Marcello Bastéa-Forte
135+ - [serialize-javascript](https://github.com/yahoo/serialize-javascript) by Eric Ferraiuolo
136+ - [jsesc](https://github.com/mathiasbynens/jsesc) by Mathias Bynens
137+ - [superjson](https://github.com/blitz-js/superjson) by Blitz
135138
136139## License
137140
0 commit comments