Skip to content

Commit 22e4976

Browse files
Make deserialization more explicit in usage example
1 parent 3735b1f commit 22e4976

File tree

1 file changed

+43
-40
lines changed

1 file changed

+43
-40
lines changed

README.md

Lines changed: 43 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,31 @@
22

33
Like `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

1313
Try 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

3131
let obj = { a: 1, b: 2 };
3232
obj.c = 3;
@@ -35,6 +35,9 @@ devalue(obj); // '{a:1,b:2,c:3}'
3535

3636
obj.self = obj;
3737
devalue(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
4548
try {
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
6467
const state = {
65-
userinput: `</script><script src='https://evil.com/mwahaha.js'>`
68+
userinput: `</script><script src='https://evil.com/mwahaha.js'>`,
6669
};
6770

6871
const 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
105108
This, 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
125128
Using `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

Comments
 (0)