Skip to content

Commit

Permalink
fix: validate path
Browse files Browse the repository at this point in the history
Validate path navigation rules or node and when creating/updating data nodes.

Fixes goldibex#131
  • Loading branch information
dinoboff committed Oct 7, 2017
1 parent 986d743 commit c0d76dd
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 8 deletions.
5 changes: 5 additions & 0 deletions lib/database/ruleset.js
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,8 @@ class RulesetNode {
* @return {{child: RulesetNode, wildchildren: object}|void}
*/
$child(name, wildchildren) {
paths.mustBeValid(name);

wildchildren = wildchildren || {};

const parts = paths.split(name);
Expand Down Expand Up @@ -370,6 +372,9 @@ class RulesetNode {
* @param {function(path: string, rules: RulesetNode, wildchildren: object): boolean} cb Receive each node traversed.
*/
$traverse(path, wildchildren, cb) {

paths.mustBeValid(path);

let currentPath = '';
let currentRules = this;

Expand Down
26 changes: 19 additions & 7 deletions lib/database/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,15 +110,21 @@ class DataNode {

const keys = value['.value'] === undefined ? Object.keys(value) : [];

keys.filter(isValidKey).forEach(key => {
const childNode = DataNode.from(value[key], undefined, now);
keys
.filter(key => key !== '.value' && key !== '.priority')
.forEach(key => {
if (!isValidKey(key)) {
throw new Error(`Invalid key "${key}"; it must not include [${invalidChar.join(',')}]`);
}

if (childNode.$isNull()) {
return;
}
const childNode = DataNode.from(value[key], undefined, now);

this[key] = childNode;
});
if (childNode.$isNull()) {
return;
}

this[key] = childNode;
});

if (this[valueKey] === undefined && Object.keys(this).length === 0) {
this[valueKey] = null;
Expand Down Expand Up @@ -259,6 +265,8 @@ class DataNode {
* @return {DataNode}
*/
$child(path) {
paths.mustBeValid(path);

return paths.split(path).reduce(
(parent, key) => parent[key] || DataNode.null(),
this
Expand All @@ -276,6 +284,8 @@ class DataNode {
*/
$set(path, value, priority, now) {

paths.mustBeValid(path);

path = paths.trim(path);
now = now || Date.now();

Expand Down Expand Up @@ -343,6 +353,8 @@ class DataNode {
*/
$remove(path, now) {

paths.mustBeValid(path);

path = paths.trim(path);

if (!path) {
Expand Down
12 changes: 12 additions & 0 deletions lib/paths.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@

'use strict';

const invalidChar = ['.', '#', '$', '[', ']'];

exports.isValid = function(path) {
return invalidChar.some(char => path.includes(char)) === false;
};

exports.mustBeValid = function(path) {
if (!exports.isValid(path)) {
throw new Error(`Invalid location "${path}" contains one of [${invalidChar.join(', ')}]`);
}
};

exports.trimLeft = function(path) {
path = path || '';

Expand Down
20 changes: 19 additions & 1 deletion test/spec/lib/database/ruleset.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const invalidRulesets = {
},
otherStuff: true
},
'include invalid index': {
'includes an invalid index': {
rules: {
'.read': true,
'.indexOn': true
Expand Down Expand Up @@ -267,6 +267,15 @@ describe('Ruleset', function() {
expect(child.wildchildren).to.eql({$b: 'foo'});
});

describe('should throw when the name includes an invalid character:', function() {
const rules = ruleset.create({rules: {'.read': true}});

['.', '#', '$', '[', ']'].forEach(char => {
it(`e.g. using "${char}"`, () => expect(() => rules.root.$child(`ab/c${char}d`)).to.throw());
});

});

});

describe('#$traverse', function() {
Expand Down Expand Up @@ -400,6 +409,15 @@ describe('Ruleset', function() {
expect(cb).to.have.callCount(2);
});

describe('should throw when the path includes an invalid character:', function() {
const rules = ruleset.create({rules: {'.read': true}});

['.', '#', '$', '[', ']'].forEach(char => {
it(`e.g. using "${char}"`, () => expect(() => rules.root.$traverse(`a/b${char}c`, () => {})).to.throw());
});

});

});

});
Expand Down
45 changes: 45 additions & 0 deletions test/spec/lib/database/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,16 @@ describe('store', function() {
});
});

describe('should throw when creating a node with an invalid name:', function() {

['.', '#', '$', '[', ']'].forEach(char => {
const data = {[`a${char}c`]: 1};

it(`e.g. using "${char}"`, () => expect(() => store.create(data)).to.throw());
});

});

describe('server value replacement', function() {

it('should handle time stamps', function() {
Expand Down Expand Up @@ -222,6 +232,14 @@ describe('store', function() {
expect(newRoot).not.to.have.property('b');
});

describe('should throw when the path includes an invalid character:', function() {

['.', '#', '$', '[', ']'].forEach(char => {
it(`e.g. using "${char}"`, () => expect(() => data.$set(`a${char}c`, 1)).to.throw());
});

});

});

describe('#$merge', function() {
Expand Down Expand Up @@ -271,6 +289,17 @@ describe('store', function() {
expect(data.$merge('b/c', {})).to.equal(data);
});

describe('should throw when the path includes an invalid character:', function() {

['.', '#', '$', '[', ']'].forEach(char => {
it(`e.g. using "${char}"`, () => {
expect(() => data.$merge('/', {a: 3, [`b/c/a${char}c`]: 4})).to.throw();
expect(() => data.$merge(`/a${char}c`, {a: 3})).to.throw();
});
});

});

});

describe('#$remove', function() {
Expand Down Expand Up @@ -329,6 +358,14 @@ describe('store', function() {
expect(newRoot.$value()).to.eql({a: {b: {d: true}, e: true}});
});

describe('should throw when the path includes an invalid character:', function() {

['.', '#', '$', '[', ']'].forEach(char => {
it(`e.g. using "${char}"`, () => expect(() => data.$remove(`/a${char}c`)).to.throw());
});

});

});

describe('#$child', function() {
Expand All @@ -346,6 +383,14 @@ describe('store', function() {
expect(data.$child('foo/bar').$value()).to.equal(null);
});

describe('should throw when the path includes an invalid character:', function() {

['.', '#', '$', '[', ']'].forEach(char => {
it(`e.g. using "${char}"`, () => expect(() => data.$child(`a${char}c`)).to.throw());
});

});

});

});

0 comments on commit c0d76dd

Please sign in to comment.