added intercompute deep for large-scale security concerns regarding exposure

This commit is contained in:
Theodor Diaconu 2016-10-21 14:01:27 +03:00
parent 9cc17ff602
commit 06c28112c5
3 changed files with 102 additions and 7 deletions

View file

@ -6,6 +6,7 @@ import enforceMaxDepth from './lib/enforceMaxDepth.js';
import enforceMaxLimit from './lib/enforceMaxLimit.js';
import intersectDeep from './lib/intersectDeep.js';
import computeDeepFunctions from './lib/computeDeepFunctions.js';
import intercomputeDeep from './lib/intercomputeDeep.js';
import deepClone from '../query/lib/deepClone';
import restrictFieldsFn from './lib/restrictFields.js';
import restrictLinks from './lib/restrictLinks.js';
@ -83,7 +84,7 @@ export default class Exposure {
return body;
}
return intersectDeep(this.getBody(userId), body);
return intercomputeDeep(this.getBody(userId), body);
}
/**
@ -95,12 +96,12 @@ export default class Exposure {
}
if (_.isFunction(this.config.body)) {
return computeDeepFunctions(
return deepClone(
this.config.body.call(this, userId),
userId
);
} else {
return computeDeepFunctions(this.config.body, userId);
return deepClone(this.config.body, userId);
}
}

View file

@ -0,0 +1,48 @@
import deepClone from '../../query/lib/deepClone';
/**
* Deep Inter Computation
*/
export default function intercomputeDeep(main, second, ...args) {
let object = {};
_.each(main, (value, key) => {
if (second[key] !== undefined) {
// if the main value is a function, we run it.
if (_.isFunction(value)) {
value = value.call(null, ...args);
}
// if the main value is undefined or false, we skip the merge
if (value === undefined || value === false) {
return;
}
// if the main value is an object
if (_.isObject(value)) {
if (_.isObject(second[key])) {
// if the second one is an object as well we run recursively run the intersection
object[key] = intercomputeDeep(value, second[key], ...args);
}
// if it is not, then we will ignore it, because it won't make sense.
// to merge {a: 1} with 1.
return;
}
// if the main value is not an object, a truthy value like 1
if (_.isObject(second[key])) {
// if the second value is an object, then we will keep it.
// this won't cause problem with deep nesting because
// when you specify links you will have the main value as an object
object[key] = deepClone(second[key]);
} else {
// if the second value is not an object, we just store the first value
object[key] = value;
}
}
});
return object;
}

View file

@ -2,6 +2,7 @@ import restrictFields from '../../lib/restrictFields.js';
import enforceMaxLimit from '../../lib/enforceMaxLimit.js';
import intersectDeep from '../../lib/intersectDeep.js';
import computeDeepFunctions from '../../lib/computeDeepFunctions.js';
import intercomputeDeep from '../../lib/intercomputeDeep.js';
import enforceMaxDepth, {getDepth} from '../../lib/enforceMaxDepth.js';
import CollectionNode from '../../../query/nodes/collectionNode.js';
@ -200,7 +201,7 @@ describe('Unit Tests', function () {
Object.freeze(obj1);
Object.freeze(obj2);
const result = intersectDeep(obj1, obj2);
const result = intercomputeDeep(obj1, obj2);
assert.isObject(result);
assert.equal(result.a, 1);
@ -214,9 +215,7 @@ describe('Unit Tests', function () {
assert.isUndefined(result.d.d1.d12);
assert.isUndefined(result.d.d2);
assert.isUndefined(result.testUndefined);
assert.isObject(result.d.d1.d13);
assert.equal(result.d.d1.d13.d131, 1);
assert.isUndefined(result.d.d1.d13);
});
it('Should compute functions nested', function () {
@ -237,5 +236,52 @@ describe('Unit Tests', function () {
assert.equal(newObject.value.item, 'test');
assert.isObject(newObject.b.value);
assert.equal(newObject.b.value.item, 'test');
});
it('Should work intersect with computation and with infinite recursion avoidance', function () {
const link2 = (item) => {
return {
item,
link1
}
};
const link1 = (item) => {
return {
item,
link2
}
};
const obj1 = {
a: 1,
link1
};
const obj2 = {
a: {
a1: 1
},
link1: {
item: 1,
link2: {
item: 1,
link1: {
item: 1
}
}
}
};
const result = intercomputeDeep(obj1, obj2, 'test');
assert.isObject(result.a);
assert.isDefined(result.a.a1);
assert.isObject(result.link1);
assert.equal(result.link1.item, 'test');
assert.isObject(result.link1.link2);
assert.equal(result.link1.link2.item, 'test');
assert.isObject(result.link1.link2.link1);
assert.equal(result.link1.link2.link1.item, 'test');
})
});