├── .gitignore ├── .npmignore ├── index.js ├── .travis.yml ├── lib └── index.js ├── package.json ├── README.md └── tests └── index_test.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules 3 | coverage -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .travis.yml 3 | node_modules 4 | coverage 5 | tests -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | module.exports = require('./lib/index.js'); -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - 0.12 5 | 6 | before_script: 7 | - npm install -g istanbul mocha 8 | 9 | after_script: 10 | - npm run coveralls -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _contentLength = { 4 | DEFAULT_MAX_LENGTH: 999, 5 | DEFAULT_ERROR_STATUS: 400, 6 | DEFAULT_ERROR_MESSAGE: "Invalid payload; too big." 7 | }; 8 | 9 | var _validateMax = function (opts) { 10 | 11 | var _opts = opts || {}; 12 | 13 | var _maxLength = _opts.max || _contentLength.DEFAULT_MAX_LENGTH; 14 | var _status = _opts.status || _contentLength.DEFAULT_ERROR_STATUS; 15 | var _message = _opts.message || _contentLength.DEFAULT_ERROR_MESSAGE; 16 | 17 | var _middleware = function(request, response, next) { 18 | var _contentLength = request.headers['content-length'] ? parseInt(request.headers['content-length']) : null; 19 | 20 | if (_contentLength > _maxLength) { 21 | 22 | response.status(_status).json({message: _message}); 23 | 24 | return; 25 | } 26 | 27 | next(); 28 | } 29 | 30 | return _middleware; 31 | } 32 | 33 | exports.validateMax = _validateMax; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express-content-length-validator", 3 | "version": "1.0.0", 4 | "description": "Make sure your application is not vulnerable to large payload attacks", 5 | "main": "./lib/index.js", 6 | "scripts": { 7 | "test": "mocha ./tests/*_test.js --recursive --check-leaks --reporter min", 8 | "coverage": "istanbul cover node_modules/mocha/bin/_mocha -- tests/*_test.js", 9 | "coveralls": "istanbul cover ./node_modules/mocha/bin/_mocha -- tests/*_test.js --report lcovonly && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/ericmdantas/express-content-length-validator.git" 14 | }, 15 | "keywords": [ 16 | "express", 17 | "validator", 18 | "content-length", 19 | "payload", 20 | "attack", 21 | "express-validator", 22 | "middleware", 23 | "express-content-length-validator" 24 | ], 25 | "author": "Eric Mendes Dantas", 26 | "license": "MIT", 27 | "bugs": { 28 | "url": "https://github.com/ericmdantas/express-content-length-validator/issues" 29 | }, 30 | "homepage": "https://github.com/ericmdantas/express-content-length-validator", 31 | "dependencies": {}, 32 | "devDependencies": { 33 | "chai": "^1.10.0", 34 | "coveralls": "^2.11.2", 35 | "istanbul": "^0.3.5", 36 | "mocha": "^2.1.0", 37 | "mocha-lcov-reporter": "0.0.1" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # express-content-length-validator 2 | 3 | [![Build Status](https://travis-ci.org/ericmdantas/express-content-length-validator.svg?branch=master)](https://travis-ci.org/ericmdantas/express-content-length-validator) 4 | [![Coverage Status](https://coveralls.io/repos/ericmdantas/express-content-length-validator/badge.svg)](https://coveralls.io/r/ericmdantas/express-content-length-validator) 5 | 6 | Make sure your application is not vulnerable to large payload attacks 7 | 8 | 9 | 10 | # install 11 | 12 | ```$ npm install express-content-length-validator --save``` 13 | 14 | 15 | 16 | # api 17 | 18 | Once you've gotten the content-length module: 19 | 20 | ```js 21 | 22 | var contentLength = require('express-content-length-validator'); 23 | 24 | ``` 25 | 26 | You'll have a single function to work with: ```validateMax```. 27 | 28 | ## contentLength.validateMax(options) 29 | 30 | ```options``` is an object with three properties: 31 | 32 | - ```max```, which defaults to 999; 33 | - ```status```, which defaults to 400; 34 | - ```message```, which defaults to "Invalid payload; too big.". 35 | 36 | 37 | # usage as a middleware 38 | 39 | ```js 40 | 41 | var contentLength = require('express-content-length-validator'); 42 | var app = require('express')(); 43 | var MAX_CONTENT_LENGTH_ACCEPTED = 9999; 44 | 45 | app.use(contentLength.validateMax({max: MAX_CONTENT_LENGTH_ACCEPTED, status: 400, message: "stop it!"})); // max size accepted for the content-length 46 | 47 | // and then, when you're checking the routes 48 | 49 | app 50 | .post('/some/url/here', function(req, res) 51 | { 52 | /*all is good, the content-length is less than the expected 53 | so you can keep with your business logic*/ 54 | }); 55 | 56 | app.listen(8080); 57 | 58 | ``` 59 | 60 | 61 | 62 | # usage per endpoint 63 | 64 | ```js 65 | 66 | var contentLength = require('express-content-length-validator'); 67 | var app = require('express')(); 68 | var MAX_CONTENT_LENGTH_ACCEPTED = 9999; 69 | 70 | app.post('/some/url/here', contentLength.validateMax({max: MAX_CONTENT_LENGTH_ACCEPTED, status: 400, message: "send a smaller json, will ya?"}), function(req, res) 71 | { 72 | /*all is good, the content-length is less than the expected 73 | so you can keep with your business logic*/ 74 | }); 75 | 76 | app.listen(8080); 77 | ``` 78 | 79 | 80 | # It's that easy =] 81 | 82 | 83 | # license 84 | 85 | MIT -------------------------------------------------------------------------------- /tests/index_test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var _validator = require('../index'); 4 | var expect = require('chai').expect; 5 | 6 | var ERROR_MESSAGE_DEFAULT = "Invalid payload; too big."; 7 | 8 | describe('validator', function(){ 9 | describe('validateMax - default length 999', function () { 10 | it('should call next - no content-length', function () { 11 | var _called = false; 12 | var _endCalled = false; 13 | var _req = {headers: {}}; 14 | var _res = {status: function(){ expect(arguments[0]).to.equal(400); return {json: function(error){_endCalled = true; expect(error.message).to.equal(ERROR_MESSAGE_DEFAULT)}}}}; 15 | var _next = function(){_called = true;}; 16 | 17 | _validator.validateMax()(_req, _res, _next); 18 | 19 | expect(_called).to.be.true; 20 | expect(_endCalled).to.be.false; 21 | }); 22 | 23 | it('should not call next - length is bigger than what was expected', function () { 24 | var _called = false; 25 | var _endCalled = false; 26 | var _req = {headers: {'content-length': '1000'}}; 27 | var _res = {status: function(){ expect(arguments[0]).to.equal(400); return {json: function(error){_endCalled = true; expect(error.message).to.equal(ERROR_MESSAGE_DEFAULT)}}}}; 28 | var _next = function(){_called = true;}; 29 | 30 | _validator.validateMax()(_req, _res, _next); 31 | 32 | expect(_called).to.be.false; 33 | expect(_endCalled).to.be.true; 34 | }); 35 | 36 | it('should call next correctly', function () { 37 | var _called = false; 38 | var _endCalled = false; 39 | var _req = {headers: {'content-length': '999'}}; 40 | var _res = {status: function(){ expect(arguments[0]).to.equal(400); return {json: function(error){_endCalled = true; expect(error.message).to.equal(ERROR_MESSAGE_DEFAULT)}}}}; 41 | var _next = function(){_called = true;}; 42 | 43 | _validator.validateMax()(_req, _res, _next); 44 | 45 | expect(_called).to.be.true; 46 | expect(_endCalled).to.be.false; 47 | }); 48 | }); 49 | 50 | describe('validateMax - specific content length', function(){ 51 | it('should call next - no content-length', function(){ 52 | var _called = false; 53 | var _endCalled = false; 54 | var _req = {headers: {}}; 55 | var _res = {status: function(){ expect(arguments[0]).to.equal(400); return {json: function(error){_endCalled = true; expect(error.message).to.equal(ERROR_MESSAGE_DEFAULT)}}}}; 56 | var _next = function(){_called = true;}; 57 | 58 | _validator.validateMax(100)(_req, _res, _next); 59 | 60 | expect(_called).to.be.true; 61 | expect(_endCalled).to.be.false; 62 | }); 63 | 64 | it('should not call next, content-length bigger than expected', function(){ 65 | var _called = false; 66 | var _endCalled = false; 67 | var _req = {headers: {'content-length': '101'}}; 68 | var _res = {status: function(){ expect(arguments[0]).to.equal(400); return {json: function(error){_endCalled = true; expect(error.message).to.equal(ERROR_MESSAGE_DEFAULT)}}}}; 69 | var _next = function(){_called = true;}; 70 | 71 | _validator.validateMax({max: 100})(_req, _res, _next); 72 | 73 | expect(_called).to.be.false; 74 | expect(_endCalled).to.be.true; 75 | }); 76 | 77 | it('should call next correctly', function(){ 78 | var _called = false; 79 | var _endCalled = false; 80 | var _req = {headers: {'content-length': '99'}}; 81 | var _res = {status: function(){ expect(arguments[0]).to.equal(400); return {json: function(error){_endCalled = true; expect(error.message).to.equal(ERROR_MESSAGE_DEFAULT)}}}}; 82 | var _next = function(){_called = true;}; 83 | 84 | _validator.validateMax({max: 100})(_req, _res, _next); 85 | 86 | expect(_called).to.be.true; 87 | expect(_endCalled).to.be.false; 88 | }); 89 | }) 90 | 91 | describe('status', function(){ 92 | it('should call the status with the correct status', function(){ 93 | var _called = false; 94 | var _endCalled = false; 95 | var _req = {headers: {'content-length': '101'}}; 96 | var _res = {status: function(){ expect(arguments[0]).to.equal(500); return {json: function(error){_endCalled = true; expect(error.message).to.equal(ERROR_MESSAGE_DEFAULT)}}}}; 97 | var _next = function(){_called = true;}; 98 | 99 | _validator.validateMax({max: 100, status: 500})(_req, _res, _next); 100 | 101 | expect(_called).to.be.false; 102 | expect(_endCalled).to.be.true; 103 | }); 104 | }) 105 | 106 | describe('message', function(){ 107 | it('should call the json with the correct message', function(){ 108 | var _called = false; 109 | var _endCalled = false; 110 | var _req = {headers: {'content-length': '101'}}; 111 | var _res = {status: function(){ expect(arguments[0]).to.equal(500); return {json: function(error){_endCalled = true; expect(error.message).to.equal("stop it :(")}}}}; 112 | var _next = function(){_called = true;}; 113 | 114 | _validator.validateMax({max: 100, status: 500, message: "stop it :("})(_req, _res, _next); 115 | 116 | expect(_called).to.be.false; 117 | expect(_endCalled).to.be.true; 118 | }); 119 | }) 120 | }) --------------------------------------------------------------------------------