Skip to content

Commit 64fcb14

Browse files
committed
Added 'has' method to check for prohibited characters.
1 parent 0d526ab commit 64fcb14

File tree

5 files changed

+155
-27
lines changed

5 files changed

+155
-27
lines changed

.jshintrc

-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
"afterEach": false,
2222
"beforeEach": false,
2323
"describe": false,
24-
"expect": false,
2524
"it": false
2625
}
2726
}

README.md

+19
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,25 @@ app.use(mongoSanitize({
3838

3939
```
4040

41+
You can also bypass the middleware and use the module directly:
42+
43+
``` js
44+
var mongoSanitize = require('express-mongo-sanitize');
45+
46+
var payload = {...};
47+
48+
// Remove any keys containing prohibited characters
49+
mongoSanitize.sanitize(payload);
50+
51+
// Replace any prohibited characters in keys
52+
mongoSanitize.sanitize(payload, {
53+
replaceWith: '_'
54+
});
55+
56+
// Check if the payload has keys with prohibited characters
57+
var hasProhibited = mongoSanitize.has(payload);
58+
```
59+
4160
## What?
4261

4362
This module searches for any keys in objects that begin with a `$` sign or contain a `.`, from `req.body`, `req.query` or `req.params`. It can then either:

index.js

+47-26
Original file line numberDiff line numberDiff line change
@@ -3,43 +3,63 @@
33
var TEST_REGEX = /^\$|\./,
44
REPLACE_REGEX = /^\$|\./g;
55

6-
var sanitize = function(val, options) {
6+
var withEach = function(target, cb) {
7+
var act = function(obj) {
8+
if(Array.isArray(obj)) {
9+
obj.forEach(act);
10+
11+
} else if(obj instanceof Object) {
12+
Object.keys(obj).forEach(function(key) {
13+
var val = obj[key];
14+
var shouldRecurse = cb(obj, val, key);
15+
if(shouldRecurse) {
16+
act(obj[key]);
17+
}
18+
});
19+
}
20+
};
21+
22+
act(target);
23+
};
24+
25+
var has = function(target) {
26+
var hasProhibited = false;
27+
withEach(target, function(obj, val, key) {
28+
if(TEST_REGEX.test(key)) {
29+
hasProhibited = true;
30+
return false;
31+
} else {
32+
return true;
33+
}
34+
});
35+
36+
return hasProhibited;
37+
};
38+
39+
var sanitize = function(target, options) {
740
options = options || {};
841

942
var replaceWith = null;
1043
if(!(TEST_REGEX.test(options.replaceWith))) {
1144
replaceWith = options.replaceWith;
1245
}
1346

14-
var act = function(val) {
15-
if(Array.isArray(val)) {
16-
val.forEach(act);
17-
18-
} else if(val instanceof Object) {
19-
Object.keys(val).forEach(function(key) {
20-
var v = val[key];
21-
var noRecurse = false;
22-
23-
if(TEST_REGEX.test(key)) {
24-
delete val[key];
25-
if(replaceWith) {
26-
val[key.replace(REPLACE_REGEX, replaceWith)] = v;
27-
} else {
28-
noRecurse = true;
29-
}
30-
}
47+
withEach(target, function(obj, val, key) {
48+
var shouldRecurse = true;
3149

32-
if(!noRecurse) {
33-
act(v);
34-
}
35-
36-
});
50+
if(TEST_REGEX.test(key)) {
51+
delete obj[key];
52+
if(replaceWith) {
53+
obj[key.replace(REPLACE_REGEX, replaceWith)] = val;
54+
} else {
55+
shouldRecurse = false;
56+
}
3757
}
3858

39-
return val;
40-
};
59+
return shouldRecurse;
60+
});
4161

42-
return act(val);
62+
return target;
4363
};
4464

4565
var middleware = function(options) {
@@ -55,3 +75,4 @@ var middleware = function(options) {
5575

5676
module.exports = middleware;
5777
module.exports.sanitize = sanitize;
78+
module.exports.has = has;

package.json

+3
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,8 @@
3232
"express": "^4.13.3",
3333
"mocha": "^2.3.3",
3434
"supertest": "^1.1.0"
35+
},
36+
"dependencies": {
37+
"chai": "^3.4.1"
3538
}
3639
}

test.js

+86
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
var request = require('supertest'),
44
express = require('express'),
55
bodyParser = require('body-parser'),
6+
expect = require('chai').expect,
67
sanitize = require('./index.js');
78

89
describe('Express Mongo Sanitize', function() {
@@ -391,4 +392,89 @@ describe('Express Mongo Sanitize', function() {
391392
}, done);
392393
});
393394
});
395+
396+
describe('Has Prohibited Keys', function() {
397+
it('should return true if the object has a key beginning with a `$`', function() {
398+
var input = {
399+
$prohibited: 'key'
400+
};
401+
expect(sanitize.has(input)).to.be.true;
402+
});
403+
404+
it('should return true if the object has a key containing a `.`', function() {
405+
var input = {
406+
'prohibited.key': 'value'
407+
};
408+
expect(sanitize.has(input)).to.be.true;
409+
});
410+
411+
it('should return true if the object has a nested key beginning with a `$`', function() {
412+
var input = {
413+
nested: {
414+
$prohibited: 'key'
415+
}
416+
};
417+
expect(sanitize.has(input)).to.be.true;
418+
});
419+
420+
it('should return true if the object has a nested key containing a `.`', function() {
421+
var input = {
422+
nested: {
423+
'prohibited.key': 'value'
424+
}
425+
};
426+
expect(sanitize.has(input)).to.be.true;
427+
});
428+
429+
it('should return true if the array contains an object with a key beginning with a `$`', function() {
430+
var input = [{
431+
$prohibited: 'key'
432+
}];
433+
expect(sanitize.has(input)).to.be.true;
434+
});
435+
436+
it('should return true if the array contains an object with a key containing a `.`', function() {
437+
var input = [{
438+
'prohibited.key': 'value'
439+
}];
440+
expect(sanitize.has(input)).to.be.true;
441+
});
442+
443+
it('should return true if the payload contains a deeply nested object with a key beginning with a `$`', function() {
444+
var input = [{
445+
some: {
446+
deeply: [{
447+
nested: {
448+
$prohibited: 'key'
449+
}
450+
}]
451+
}
452+
}];
453+
expect(sanitize.has(input)).to.be.true;
454+
});
455+
456+
it('should return true if the payload contains a deeply nested object with a key containing a `.`', function() {
457+
var input = [{
458+
some: {
459+
deeply: [{
460+
nested: {
461+
'prohibited..key': 'key'
462+
}
463+
}]
464+
}
465+
}];
466+
expect(sanitize.has(input)).to.be.true;
467+
});
468+
469+
it('should return false if the payload doesn\'t contain any prohibited characters', function() {
470+
var input = {
471+
some: {
472+
nested: [{
473+
data: 'panda'
474+
}]
475+
}
476+
};
477+
expect(sanitize.has(input)).to.be.false;
478+
});
479+
});
394480
});

0 commit comments

Comments
 (0)