Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add @elastic/safer-lodash-set as an alternative to lodash.set #67452

Merged
merged 63 commits into from
Jul 15, 2020
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
05d9664
Initial inline of @elastic/safer-lodash-set
watson May 26, 2020
fafb173
Comply with Kibana monorepo rules andi styling
watson May 26, 2020
8358e2b
Refactor all use of lodash.set to @elastic/safer-lodash-set
watson May 27, 2020
f4f7eeb
Add lodash/fp to ESLint blacklist
watson May 27, 2020
4d6d865
Remove standardjs badge from README.md
watson May 27, 2020
d41353c
Rename @elastic/safer-lodash-set to @kbn/safer-lodash-set
watson May 27, 2020
3619c8e
For now we don't want to publish this module
watson May 27, 2020
49d8875
Merge branch 'master' into safer-lodash-set
watson Jun 10, 2020
e68344a
Remove duplicate entry in x-pack/package.json
watson Jun 10, 2020
8dd6a76
Merge branch 'master' into safer-lodash-set
watson Jun 25, 2020
8e54d46
Rename @kbn namespace back to @elastic
watson Jun 25, 2020
48ec297
Add TypeScript tests
watson Jun 25, 2020
3415afd
Merge branch 'master' into safer-lodash-set
watson Jun 29, 2020
c1bc23e
Fix new wrong uses of Lodash from master
watson Jun 29, 2020
5eb4809
Update licenses
watson Jun 30, 2020
eddf9ff
Expose TypeScript types in package.json
watson Jun 30, 2020
2e1b518
Merge branch 'master' into safer-lodash-set
watson Jun 30, 2020
a55d85c
Add license header to script files
watson Jun 30, 2020
c12b6bd
Run package tests as part of CI
watson Jul 1, 2020
899bea0
Merge branch 'master' into safer-lodash-set
watson Jul 1, 2020
17719ff
Ups
watson Jul 1, 2020
f577950
Merge branch 'master' into safer-lodash-set
watson Jul 2, 2020
20d7b10
Allow ESLint to test the lodash folder
watson Jul 2, 2020
524bf02
Re-adding package to x-pack package.json
watson Jul 2, 2020
f2929cb
ups
watson Jul 2, 2020
2d0eefb
Merge branch 'master' into safer-lodash-set
watson Jul 3, 2020
3d21a0d
Remove unchanged lodash files and rely on peerDependency
watson Jul 4, 2020
b403435
Add support for lodash/fp
watson Jul 4, 2020
e3c12d5
Merge branch 'master' into safer-lodash-set
watson Jul 4, 2020
dd254fb
Use @elastic/safer-lodash-set/fp version instead of lodash/fp
watson Jul 4, 2020
5375150
Apply suggestions from code review
watson Jul 7, 2020
7f93093
Merge branch 'master' into safer-lodash-set
watson Jul 7, 2020
88d14ea
Fix typos
watson Jul 7, 2020
4cc8d30
Use bash instead of sh for scripts
watson Jul 7, 2020
c85b8f7
Actually run the package tests
watson Jul 7, 2020
664e8b2
Ensure linebreaks are rendered correctly
watson Jul 7, 2020
86c15a2
Throw if prototype is set on arrow-functions
watson Jul 7, 2020
2af8ae0
Use lodash.isFunction instead of typeof
watson Jul 7, 2020
2ac1333
Fix typo in LICENSE
watson Jul 7, 2020
7b1c024
Fix typo in comment
watson Jul 7, 2020
cf11b62
Fix .npmignore
watson Jul 7, 2020
e0d54fa
Add tsconfig.json
watson Jul 7, 2020
2621244
Use tape instead of assert
watson Jul 8, 2020
b942bae
Fix tsd issue related to new tsconfig.json file
watson Jul 8, 2020
747c69e
Remove private field from package.json
watson Jul 8, 2020
adbaee6
forgot with tape
watson Jul 8, 2020
2f31347
Bump tsd
watson Jul 8, 2020
c3b4351
Fix bug with fp api
watson Jul 8, 2020
cea10a8
Add fp TypeScript types
watson Jul 8, 2020
54239dd
Update saved state
watson Jul 8, 2020
ccf2b4d
Fix README.md to reflect reality
watson Jul 8, 2020
6d4da53
Extend tsconfig.json from root
watson Jul 9, 2020
dd35300
Merge branch 'master' into safer-lodash-set
watson Jul 9, 2020
34316df
Merge branch 'master' into safer-lodash-set
watson Jul 9, 2020
a33c7ed
Whitelist files for casing
watson Jul 9, 2020
93ff996
Merge branch 'master' into safer-lodash-set
elasticmachine Jul 9, 2020
7dd9e3e
Merge branch 'master' into safer-lodash-set
elasticmachine Jul 10, 2020
fb7c63d
Merge branch 'master' into pr-67452-safer
azasypkin Jul 14, 2020
41c6acf
Disable ESLint `var` warning to be closer to the lodash source code.
azasypkin Jul 14, 2020
daf8eb0
Merge branch 'master' into pr-67452-safer
azasypkin Jul 14, 2020
9b99a23
Merge branch 'master' into pr-67452-safer
azasypkin Jul 15, 2020
415fdd2
Merge branch 'master' into safer-lodash-set
elasticmachine Jul 15, 2020
1b4d708
Update yarn.lock.
azasypkin Jul 15, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ target
/x-pack/legacy/plugins/maps/public/vendor/**

# package overrides
/packages/kbn-safer-lodash-set/lodash/*
/packages/eslint-config-kibana
/packages/kbn-interpreter/src/common/lib/grammar.js
/packages/kbn-plugin-generator/sao_template/template
Expand All @@ -48,4 +49,3 @@ target
/packages/kbn-ui-framework/dist
/packages/kbn-ui-framework/doc_site/build
/packages/kbn-ui-framework/generator-kui/*/templates/

120 changes: 120 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,126 @@ module.exports = {
files: ['test/harden/*.js'],
rules: allMochaRulesOff,
},
{
files: ['**/*.{js,mjs,ts,tsx}'],
rules: {
'no-restricted-imports': [
2,
{
paths: [
{
name: 'lodash',
importNames: ['set', 'setWith'],
message: 'Please use @kbn/safer-lodash-set instead',
},
{
name: 'lodash.set',
message: 'Please use @kbn/safer-lodash-set instead',
},
{
name: 'lodash.setwith',
message: 'Please use @kbn/safer-lodash-set instead',
},
{
name: 'lodash/set',
message: 'Please use @kbn/safer-lodash-set instead',
},
{
name: 'lodash/setWith',
message: 'Please use @kbn/safer-lodash-set instead',
},
{
name: 'lodash/fp',
importNames: ['set', 'setWith', 'assoc', 'assocPath'],
message: 'Please use @kbn/safer-lodash-set instead',
},
{
name: 'lodash/fp/set',
message: 'Please use @kbn/safer-lodash-set instead',
},
{
name: 'lodash/fp/setWith',
message: 'Please use @kbn/safer-lodash-set instead',
},
{
name: 'lodash/fp/assoc',
message: 'Please use @kbn/safer-lodash-set instead',
},
{
name: 'lodash/fp/assocPath',
message: 'Please use @kbn/safer-lodash-set instead',
},
],
},
],
'no-restricted-modules': [
2,
{
paths: [
{
name: 'lodash.set',
message: 'Please use @kbn/safer-lodash-set instead',
},
{
name: 'lodash.setwith',
message: 'Please use @kbn/safer-lodash-set instead',
},
{
name: 'lodash/set',
message: 'Please use @kbn/safer-lodash-set instead',
},
{
name: 'lodash/setWith',
message: 'Please use @kbn/safer-lodash-set instead',
},
],
},
],
'no-restricted-properties': [
2,
{
object: 'lodash',
property: 'set',
message: 'Please use @kbn/safer-lodash-set instead',
},
{
object: '_',
property: 'set',
message: 'Please use @kbn/safer-lodash-set instead',
},
{
object: 'lodash',
property: 'setWith',
message: 'Please use @kbn/safer-lodash-set instead',
},
{
object: '_',
property: 'setWith',
message: 'Please use @kbn/safer-lodash-set instead',
},
{
object: 'lodash',
property: 'assoc',
message: 'Please use @kbn/safer-lodash-set instead',
},
{
object: '_',
property: 'assoc',
message: 'Please use @kbn/safer-lodash-set instead',
},
{
object: 'lodash',
property: 'assocPath',
message: 'Please use @kbn/safer-lodash-set instead',
},
{
object: '_',
property: 'assocPath',
message: 'Please use @kbn/safer-lodash-set instead',
},
],
},
},

/**
* APM overrides
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@
"@elastic/good": "8.1.1-kibana2",
"@elastic/numeral": "^2.5.0",
"@elastic/request-crypto": "1.1.4",
"@kbn/safer-lodash-set": "0.0.0",
"@elastic/ui-ace": "0.2.3",
"@hapi/good-squeeze": "5.2.1",
"@hapi/wreck": "^15.0.2",
Expand Down
2 changes: 2 additions & 0 deletions packages/kbn-safer-lodash-set/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.tmp
node_modules
2 changes: 2 additions & 0 deletions packages/kbn-safer-lodash-set/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
test.js
scripts
21 changes: 21 additions & 0 deletions packages/kbn-safer-lodash-set/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2020 Elasticsearch BV, JS Foundation, and other contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
95 changes: 95 additions & 0 deletions packages/kbn-safer-lodash-set/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# @kbn/safer-lodash-set

This module adds protection against prototype pollution to the [`set`]
and [`setWith`] functions from [Lodash] and are API compatible with
Lodash v4.x.

## Example Usage

```js
const { set } = require('@elastic/safer-loadsh-set');

const object = { a: [{ b: { c: 3 } }] };

set(object, 'a[0].b.c', 4);
console.log(object.a[0].b.c); // => 4

set(object, ['x', '0', 'y', 'z'], 5);
console.log(object.x[0].y.z); // => 5
```

## API

The main module exposes two functions, `set` and `setWith`:

```js
const { set, setWith } = require('@kbn/safer-lodash-set');
```

Besides the main module, it's also possible to require each function
individually:

```js
const set = require('@kbn/safer-lodash-set/set');
const setWith = require('@kbn/safer-lodash-set/setWith');
```

The APIs of these functions are identical to the equivalent Lodash
[`set`] and [`setWith`] functions. Please refer to the Lodash
documentation for the respective functions for details.

## Limitations

The safety improvements in this module is achived by adding the
following limitations to the algorithm used to walk the `path` given as
the 2nd argument to the `set` and `setWith` functions:

### Only own properties are followed when walking the `path`

```js
const parent = { foo: 1 };
const child = { bar: 2 };

Object.setPrototypeOf(child, parent);

// Now `child` can access `foo` through prototype inheritance
console.log(child.foo); // 1

set(child, 'foo', 3);

// A different `foo` property has now been added directly to the `child`
// object and the `parent` object has not been modified:
console.log(child.foo); // 3
console.log(parent.foo); // 1
console.log(Object.prototype.hasOwnProperty.call(child, 'foo')); // true
```

### The `path` must not access function prototypes

```js
const object = {
fn1: function () {}, // regular functions has a prototype
fn2: () => {}, // arrow functions doesn't have a prototype
};

// Attempting to access any function prototype will result in an
// exception being thrown:
assert.throws(() => {
// Throws: Illegal access of function prototype
set(object, 'fn1.prototype.toString', 'bang!');
});

assert.doesNotThrow(() => {
// Will just create a fresh `prototype` property on the arrow function:
set(object, 'fn2.prototype.toString', 'bang!');
console.log(object.fn2); // '[Function: fn2] { prototype: { toString: 'bang!' } }'
});
```

## License

[MIT](LICENSE)

[`set`]: https://lodash.com/docs/4.17.15#set
[`setwith`]: https://lodash.com/docs/4.17.15#setWith
[lodash]: https://lodash.com/
21 changes: 21 additions & 0 deletions packages/kbn-safer-lodash-set/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

exports.set = require('./lodash/set');
exports.setWith = require('./lodash/setWith');
32 changes: 32 additions & 0 deletions packages/kbn-safer-lodash-set/lodash/_Hash.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
var hashClear = require('./_hashClear'),
hashDelete = require('./_hashDelete'),
hashGet = require('./_hashGet'),
hashHas = require('./_hashHas'),
hashSet = require('./_hashSet');

/**
* Creates a hash object.
*
* @private
* @constructor
* @param {Array} [entries] The key-value pairs to cache.
*/
function Hash(entries) {
var index = -1,
length = entries == null ? 0 : entries.length;

this.clear();
while (++index < length) {
var entry = entries[index];
this.set(entry[0], entry[1]);
}
}

// Add methods to `Hash`.
Hash.prototype.clear = hashClear;
Hash.prototype['delete'] = hashDelete;
Hash.prototype.get = hashGet;
Hash.prototype.has = hashHas;
Hash.prototype.set = hashSet;

module.exports = Hash;
32 changes: 32 additions & 0 deletions packages/kbn-safer-lodash-set/lodash/_ListCache.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
var listCacheClear = require('./_listCacheClear'),
listCacheDelete = require('./_listCacheDelete'),
listCacheGet = require('./_listCacheGet'),
listCacheHas = require('./_listCacheHas'),
listCacheSet = require('./_listCacheSet');

/**
* Creates an list cache object.
*
* @private
* @constructor
* @param {Array} [entries] The key-value pairs to cache.
*/
function ListCache(entries) {
var index = -1,
length = entries == null ? 0 : entries.length;

this.clear();
while (++index < length) {
var entry = entries[index];
this.set(entry[0], entry[1]);
}
}

// Add methods to `ListCache`.
ListCache.prototype.clear = listCacheClear;
ListCache.prototype['delete'] = listCacheDelete;
ListCache.prototype.get = listCacheGet;
ListCache.prototype.has = listCacheHas;
ListCache.prototype.set = listCacheSet;

module.exports = ListCache;
7 changes: 7 additions & 0 deletions packages/kbn-safer-lodash-set/lodash/_Map.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
var getNative = require('./_getNative'),
root = require('./_root');

/* Built-in method references that are verified to be native. */
var Map = getNative(root, 'Map');

module.exports = Map;
Loading