From 63810ca1ae1a24b08293a4d971e70e058c7a41e2 Mon Sep 17 00:00:00 2001 From: "Benjamin E. Coe" Date: Mon, 16 Mar 2020 00:08:00 -0700 Subject: [PATCH] fix: __proto__ will now be replaced with ___proto___ in parse (#258) --- index.js | 16 +++++++++++++- test/fixtures/config.json | 10 ++++++++- test/yargs-parser.js | 46 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 5c6547d9..b7a18391 100644 --- a/index.js +++ b/index.js @@ -697,6 +697,10 @@ function parse (args, opts) { if (!configuration['dot-notation']) keys = [keys.join('.')] keys.slice(0, -1).forEach(function (key, index) { + // TODO(bcoe): in the next major version of yargs, switch to + // Object.create(null) for dot notation: + key = sanitizeKey(key) + if (typeof o === 'object' && o[key] === undefined) { o[key] = {} } @@ -716,7 +720,10 @@ function parse (args, opts) { } }) - const key = keys[keys.length - 1] + // TODO(bcoe): in the next major version of yargs, switch to + // Object.create(null) for dot notation: + const key = sanitizeKey(keys[keys.length - 1]) + const isTypeArray = checkAllAliases(keys.join('.'), flags.arrays) const isValueArray = Array.isArray(value) let duplicate = configuration['duplicate-arguments-array'] @@ -1001,4 +1008,11 @@ Parser.detailed = function (args, opts) { return parse(args.slice(), opts) } +// TODO(bcoe): in the next major version of yargs, switch to +// Object.create(null) for dot notation: +function sanitizeKey (key) { + if (key === '__proto__') return '___proto___' + return key +} + module.exports = Parser diff --git a/test/fixtures/config.json b/test/fixtures/config.json index 1f571f24..7065ae61 100644 --- a/test/fixtures/config.json +++ b/test/fixtures/config.json @@ -4,5 +4,13 @@ "foo": "baz", "version": "1.0.2", "truthy": true, - "toString": "method name" + "toString": "method name", + "__proto__": { + "aaa": 99 + }, + "bar": { + "__proto__": { + "bbb": 100 + } + } } diff --git a/test/yargs-parser.js b/test/yargs-parser.js index 3e138998..217f188f 100644 --- a/test/yargs-parser.js +++ b/test/yargs-parser.js @@ -727,6 +727,25 @@ describe('yargs-parser', function () { argv.error.message.should.equal('someone set us up the bomb') }) + + it('should not pollute the prototype', function () { + const argv = parser(['--foo', 'bar'], { + alias: { + z: 'zoom' + }, + default: { + settings: jsonPath + }, + config: 'settings' + }) + + argv.should.have.property('herp', 'derp') + argv.should.have.property('zoom', 55) + argv.should.have.property('foo').and.deep.equal('bar') + + expect({}.bbb).to.equal(undefined) + expect({}.aaa).to.equal(undefined) + }) }) describe('config objects', function () { @@ -974,6 +993,13 @@ describe('yargs-parser', function () { argv.f.foo.should.eql(99) argv.f.bar.should.eql(true) }) + + it('should not pollute the prototype', function () { + parser(['-f.__proto__.foo', '99', '-x.y.__proto__.bar', '100', '--__proto__', '200']) + Object.keys({}.__proto__).length.should.equal(0) // eslint-disable-line + expect({}.foo).to.equal(undefined) + expect({}.bar).to.equal(undefined) + }) }) it('should set boolean and alias using explicit true', function () { @@ -3702,4 +3728,24 @@ describe('yargs-parser', function () { argv._.should.eql([101, 102]) }) }) + + it('should replace the key __proto__ with the key ___proto___', function () { + const argv = parser(['-f.__proto__.foo', '99', '-x.y.__proto__.bar', '100', '--__proto__', '200']) + argv.should.eql({ + _: [], + ___proto___: 200, + f: { + ___proto___: { + foo: 99 + } + }, + x: { + y: { + ___proto___: { + bar: 100 + } + } + } + }) + }) })