Skip to content

Commit b5fe325

Browse files
authored
Merge pull request from GHSA-2hj9-hg84-7g3w
Fix escaping of unsafe characters in `Error` objects and property names
2 parents 7c024fb + 431734b commit b5fe325

File tree

9 files changed

+338
-263
lines changed

9 files changed

+338
-263
lines changed

.eslintignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
coverage/*
2-
tmp/*
2+
tmp
3+
lib

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ coverage/
33
.nyc_output/
44
doc/
55
tmp/
6+
lib/
67
*.log
78
*.tgz
89
*.sh

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ The following Objects are supported
2525

2626
> **Note:** Version >3.0.0 has moved the serializeToModule method into its own
2727
> package at [serialize-to-module][]
28-
>
28+
>
2929
> Migrating from 2.x to 3.x for serialize:
3030
> ```js
3131
> // v2.x
@@ -40,6 +40,7 @@ The following Objects are supported
4040
4141
* [Methods](#methods)
4242
* [serialize](#serialize)
43+
* [serializeToModule](#serializetomodule)
4344
* [Contribution and License Agreement](#contribution-and-license-agreement)
4445
* [License](#license)
4546

package.json

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,30 @@
1818
"license": "MIT",
1919
"author": "commenthol <commenthol@gmail.com>",
2020
"main": "lib",
21+
"module": "src",
2122
"directories": {
2223
"lib": "lib",
2324
"test": "test"
2425
},
2526
"scripts": {
26-
"all": "npm run lint && npm test",
27-
"clean": "rimraf doc coverage .nyc_output node_modules *.tgz",
27+
"all": "npm run clean && npm run lint && npm run build && npm test",
28+
"build": "babel -d lib src",
29+
"clean": "rimraf lib doc coverage .nyc_output *.tgz",
2830
"coverage": "nyc -r text -r html npm test",
29-
"lint": "eslint lib test",
31+
"lint": "eslint src test",
3032
"prepublishOnly": "npm run all",
3133
"readme": "markedpp --githubid -i README.md -o README.md",
3234
"test": "mocha"
3335
},
36+
"babel": {
37+
"presets": [
38+
"@babel/preset-env"
39+
]
40+
},
3441
"eslintConfig": {
42+
"env": {
43+
"mocha": true
44+
},
3545
"extends": "standard",
3646
"plugins": [
3747
"standard"
@@ -42,15 +52,18 @@
4252
},
4353
"dependencies": {},
4454
"devDependencies": {
45-
"eslint": "^5.16.0",
46-
"eslint-config-standard": "^12.0.0",
47-
"eslint-plugin-import": "^2.17.2",
48-
"eslint-plugin-node": "^9.1.0",
49-
"eslint-plugin-promise": "^4.1.1",
50-
"eslint-plugin-standard": "^4.0.0",
51-
"mocha": "^6.1.4",
55+
"@babel/cli": "^7.7.5",
56+
"@babel/core": "^7.7.5",
57+
"@babel/preset-env": "^7.7.6",
58+
"eslint": "^6.7.2",
59+
"eslint-config-standard": "^14.1.0",
60+
"eslint-plugin-import": "^2.19.1",
61+
"eslint-plugin-node": "^10.0.0",
62+
"eslint-plugin-promise": "^4.2.1",
63+
"eslint-plugin-standard": "^4.0.1",
64+
"mocha": "^6.2.2",
5265
"nyc": "^14.1.1",
53-
"rimraf": "^2.6.3"
66+
"rimraf": "^3.0.0"
5467
},
5568
"engines": {
5669
"node": ">=4.0.0"

lib/index.js renamed to src/index.js

Lines changed: 44 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@
66
'use strict'
77

88
// dependencies
9-
var util = require('./internal/utils')
10-
var Ref = require('./internal/reference')
9+
const utils = require('./internal/utils')
10+
const Ref = require('./internal/reference')
1111

1212
/**
1313
* serializes an object to javascript
1414
*
1515
* @example <caption>serializing regex, date, buffer, ...</caption>
16-
* var serialize = require('serialize-to-js').serialize;
17-
* var obj = {
16+
* const serialize = require('serialize-to-js').serialize;
17+
* const obj = {
1818
* str: '<script>var a = 0 > 1</script>',
1919
* num: 3.1415,
2020
* bool: true,
@@ -30,10 +30,10 @@ var Ref = require('./internal/reference')
3030
* // > {str: "\u003Cscript\u003Evar a = 0 \u003E 1\u003C\u002Fscript\u003E", num: 3.1415, bool: true, nil: null, undef: undefined, obj: {foo: "bar"}, arr: [1, "2"], regexp: /^test?$/, date: new Date("2016-04-15T16:22:52.009Z"), buffer: new Buffer('ZGF0YQ==', 'base64')}
3131
*
3232
* @example <caption>serializing while respecting references</caption>
33-
* var serialize = require('serialize-to-js').serialize;
34-
* var obj = { object: { regexp: /^test?$/ } };
33+
* const serialize = require('serialize-to-js').serialize;
34+
* const obj = { object: { regexp: /^test?$/ } };
3535
* obj.reference = obj.object;
36-
* var opts = { reference: true };
36+
* const opts = { reference: true };
3737
* console.log(serialize(obj, opts));
3838
* //> {object: {regexp: /^test?$/}}
3939
* console.log(opts.references);
@@ -47,84 +47,78 @@ var Ref = require('./internal/reference')
4747
* @return {String} serialized representation of `source`
4848
*/
4949
function serialize (source, opts) {
50-
var out = ''
51-
var key
52-
var tmp
53-
var type
54-
var i
50+
let type
5551

5652
opts = opts || {}
5753
if (!opts._visited) {
5854
opts._visited = []
5955
}
6056
if (!opts._refs) {
6157
opts.references = []
62-
opts._refs = new Ref(opts.references)
58+
opts._refs = new Ref(opts.references, opts)
6359
}
6460

65-
if (util.isNull(source)) {
66-
out += 'null'
67-
} else if (util.isArray(source)) {
68-
tmp = source.map(function (item) {
69-
return serialize(item, opts)
70-
})
71-
out += '[' + tmp.join(', ') + ']'
72-
} else if (util.isFunction(source)) {
73-
tmp = source.toString()
61+
if (utils.isNull(source)) {
62+
return 'null'
63+
} else if (Array.isArray(source)) {
64+
const tmp = source.map(item => serialize(item, opts))
65+
return `[${tmp.join(', ')}]`
66+
} else if (utils.isFunction(source)) {
67+
// serializes functions only in unsafe mode!
68+
const _tmp = source.toString()
69+
const tmp = opts.unsafe ? _tmp : utils.saferFunctionString(_tmp, opts)
7470
// append function to es6 function within obj
75-
out += !/^\s*(function|\([^)]*\)\s*=>)/m.test(tmp) ? 'function ' + tmp : tmp
76-
} else if (util.isObject(source)) {
77-
if (util.isRegExp(source)) {
78-
out += 'new RegExp(' + serialize(source.source) + ', "' + source.flags + '")'
79-
} else if (util.isDate(source)) {
80-
out += 'new Date("' + source.toJSON() + '")'
81-
} else if (util.isError(source)) {
82-
out += 'new Error(' + (source.message ? '"' + source.message + '"' : '') + ')'
83-
} else if (util.isBuffer(source)) {
71+
return !/^\s*(function|\([^)]*?\)\s*=>)/m.test(tmp) ? 'function ' + tmp : tmp
72+
} else if (utils.isObject(source)) {
73+
if (utils.isRegExp(source)) {
74+
return `new RegExp(${utils.quote(source.source, opts)}, "${source.flags}")`
75+
} else if (utils.isDate(source)) {
76+
return `new Date(${utils.quote(source.toJSON(), opts)})`
77+
} else if (utils.isError(source)) {
78+
return `new Error(${utils.quote(source.message, opts)})`
79+
} else if (utils.isBuffer(source)) {
8480
// check for buffer first otherwise tests fail on node@4.4
8581
// looks like buffers are accidentially detected as typed arrays
86-
out += "Buffer.from('" + source.toString('base64') + "', 'base64')"
87-
} else if ((type = util.isTypedArray(source))) {
88-
tmp = []
89-
for (i = 0; i < source.length; i++) {
82+
return `Buffer.from('${source.toString('base64')}', 'base64')`
83+
} else if ((type = utils.isTypedArray(source))) {
84+
const tmp = []
85+
for (let i = 0; i < source.length; i++) {
9086
tmp.push(source[i])
9187
}
92-
out += 'new ' + type + '(' +
93-
'[' + tmp.join(', ') + ']' +
94-
')'
88+
return `new ${type}([${tmp.join(', ')}])`
9589
} else {
96-
tmp = []
90+
const tmp = []
9791
// copy properties if not circular
9892
if (!~opts._visited.indexOf(source)) {
9993
opts._visited.push(source)
100-
for (key in source) {
101-
if (source.hasOwnProperty(key)) {
102-
if (opts.reference && util.isObject(source[key])) {
94+
for (const key in source) {
95+
if (Object.prototype.hasOwnProperty.call(source, key)) {
96+
if (opts.reference && utils.isObject(source[key])) {
10397
opts._refs.push(key)
10498
if (!opts._refs.hasReference(source[key])) {
105-
tmp.push(Ref.wrapkey(key) + ': ' + serialize(source[key], opts))
99+
tmp.push(Ref.wrapkey(key, opts) + ': ' + serialize(source[key], opts))
106100
}
107101
opts._refs.pop()
108102
} else {
109-
tmp.push(Ref.wrapkey(key) + ': ' + serialize(source[key], opts))
103+
tmp.push(Ref.wrapkey(key, opts) + ': ' + serialize(source[key], opts))
110104
}
111105
}
112106
}
113-
out += '{' + tmp.join(', ') + '}'
114107
opts._visited.pop()
108+
return `{${tmp.join(', ')}}`
115109
} else {
116110
if (opts.ignoreCircular) {
117-
out += '{/*[Circular]*/}'
111+
return '{/*[Circular]*/}'
118112
} else {
119113
throw new Error('can not convert circular structures.')
120114
}
121115
}
122116
}
123-
} else if (util.isString(source)) {
124-
out += '"' + (opts.unsafe ? util.unsafeString(source) : util.safeString(source)) + '"'
117+
} else if (utils.isString(source)) {
118+
return utils.quote(source, opts)
125119
} else {
126-
out += '' + source
120+
return '' + source
127121
}
128-
return out
129122
}
123+
130124
module.exports = serialize

lib/internal/reference.js renamed to src/internal/reference.js

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,22 @@
55

66
'use strict'
77

8-
var KEY = /^[a-zA-Z$_][a-zA-Z$_0-9]*$/
8+
const utils = require('./utils')
9+
10+
const KEY = /^[a-zA-Z$_][a-zA-Z$_0-9]*$/
911

1012
/**
1113
* handle references
1214
* @constructor
1315
* @param {Object} references
16+
* @param {boolean} opts.unsafe
1417
*/
15-
function Ref (references) {
18+
function Ref (references, opts) {
1619
this.keys = []
1720
this.refs = []
1821
this.key = []
1922
this.references = references || []
23+
this._opts = opts || {}
2024
}
2125

2226
/**
@@ -25,8 +29,8 @@ function Ref (references) {
2529
* @param {String} key - objects key
2630
* @return {String} wrapped key in quotes if necessary
2731
*/
28-
Ref.wrapkey = function (key) {
29-
return (KEY.test(key) ? key : '"' + key.replace(/"/g, '\\"') + '"')
32+
Ref.wrapkey = function (key, opts) {
33+
return (KEY.test(key) ? key : utils.quote(key, opts))
3034
}
3135

3236
Ref.prototype = {
@@ -47,17 +51,17 @@ Ref.prototype = {
4751
* join the keys
4852
*/
4953
join: function (key) {
50-
var out = ''
54+
let out = ''
5155
key = key || this.key
5256
if (typeof key === 'string') {
5357
key = [key]
5458
}
5559

56-
key.forEach(function (k) {
60+
key.forEach(k => {
5761
if (KEY.test(k)) {
5862
out += '.' + k
5963
} else {
60-
out += '[' + Ref.wrapkey(k) + ']'
64+
out += '[' + Ref.wrapkey(k, this._opts) + ']'
6165
}
6266
})
6367
return out
@@ -69,7 +73,7 @@ Ref.prototype = {
6973
* @return {Boolean}
7074
*/
7175
hasReference: function (source) {
72-
var idx
76+
let idx
7377
if (~(idx = this.refs.indexOf(source))) {
7478
this.references.push([this.join(), this.keys[idx]])
7579
return true

0 commit comments

Comments
 (0)