Skip to content

Commit 65c5a53

Browse files
committed
setting up and securing the routes
1 parent d9ed5fa commit 65c5a53

File tree

7 files changed

+86
-47
lines changed

7 files changed

+86
-47
lines changed

app.js

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -24,41 +24,25 @@ if (cluster.isMaster && config.env === 'production') {
2424
var express = require('express');
2525
var app = express();
2626
var router = require('./routes');
27-
var helmet = require('helmet');
28-
var client = require('redis').createClient(config.redisURL);
29-
var limiter = require('express-limiter')(app, client);
27+
var express_enforces_ssl = require('express-enforces-ssl');
3028

3129
if(config.trustProxy === 'yes'){
3230
app.enable('trust proxy');
3331
}
3432

33+
if(config.enforceSSL === 'yes'){
34+
app.use(express_enforces_ssl());
35+
}
3536

36-
app.use(helmet());
37-
// no client side caching
38-
if(config.noFrontendCaching === 'yes'){
39-
app.use(helmet.noCache());
40-
}
41-
42-
limiter({
43-
path: '*',
44-
method: 'all',
45-
lookup: 'userId',
46-
total: config.rateLimit * 1,
47-
expire: config.rateLimitExpiry * 1,
48-
onRateLimited: function (req, res, next) {
49-
next({ message: 'Rate limit exceeded', statusCode: 429 });
50-
}
51-
});
52-
53-
app.use('/',router);
37+
app.use('/',router);
5438

55-
if(config.env === 'production'){
56-
log.info('Worker %d running!', cluster.worker.id);
57-
}
39+
if(config.env === 'production'){
40+
log.info('Worker %d running!', cluster.worker.id);
41+
}
5842

5943

60-
app.listen(config.port, function () {
61-
log.info('listening on port '+config.port+'!');
62-
});
44+
app.listen(config.port, function () {
45+
log.info('listening on port '+config.port+'!');
46+
});
6347

6448
}

config/development.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,11 @@ module.exports = {
1010
noFrontendCaching: process.env.NO_CACHE || 'yes',
1111
rateLimit: process.env.RATE_LIMIT || '180',
1212
rateLimitExpiry: process.env.RATE_LIMIT_EXPIRY || '3600000',
13-
redisURL: process.env.REDIS_URL || 'redis://192.168.99.100:6379/1'
13+
redisURL: process.env.REDIS_URL || 'redis://192.168.99.100:6379/1',
14+
userVerificationEndpoint: process.env.USER_VERIFICATION_API || 'http://mockbin.org/bin/9edd4bf7-bb36-47b6-adb2-54d7a7236e80',
15+
appVerificationEndpoint: process.env.APP_VERIFICATION_API || 'http://mockbin.org/bin/9edd4bf7-bb36-47b6-adb2-54d7a7236e80',
16+
letsencryptSSLVerificationURL: process.env.LETSENCRYPT_VERIFICATION_URL || '/.well-known/acme-challenge/xvArhQBSilF4V30dGUagNAZ96ASipB0b0ex0kXn0za8',
17+
letsencryptSSLVerificationBody: process.env.LETSENCRYPT_VERIFICATION_BODY || 'xvArhQBSilF4V30dGUagNAZ96ASipB0b0ex0kXn0za8._v6aFbaRYWeOmSebtlD-X4Ixf5tPsyULMsXM8HjsK-Q',
18+
maxContentLength: process.env.MAX_CONTENT_LENGTH || '9999',
19+
enforceSSL: process.env.ENFORCE_SSL || 'no'
1420
};

config/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ if(process.env.NODE_ENV === 'development'){
88
module.exports = production;
99
}else{
1010
module.exports = development;
11-
}
11+
}

config/production.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,11 @@ module.exports = {
1010
noFrontendCaching: process.env.NO_CACHE || 'yes',
1111
rateLimit: process.env.RATE_LIMIT || '180',
1212
rateLimitExpiry: process.env.RATE_LIMIT_EXPIRY || '3600000',
13-
redisURL: process.env.REDIS_URL || 'redis://192.168.99.100:6379/1'
13+
redisURL: process.env.REDIS_URL || 'redis://192.168.99.100:6379/1',
14+
userVerificationEndpoint: process.env.USER_VERIFICATION_API || 'http://mockbin.org/bin/9edd4bf7-bb36-47b6-adb2-54d7a7236e80',
15+
appVerificationEndpoint: process.env.APP_VERIFICATION_API || 'http://mockbin.org/bin/9edd4bf7-bb36-47b6-adb2-54d7a7236e80',
16+
letsencryptSSLVerificationURL: process.env.LETSENCRYPT_VERIFICATION_URL || '/.well-known/acme-challenge/xvArhQBSilF4V30dGUagNAZ96ASipB0b0ex0kXn0za8',
17+
letsencryptSSLVerificationBody: process.env.LETSENCRYPT_VERIFICATION_BODY || 'xvArhQBSilF4V30dGUagNAZ96ASipB0b0ex0kXn0za8._v6aFbaRYWeOmSebtlD-X4Ixf5tPsyULMsXM8HjsK-Q',
18+
maxContentLength: process.env.MAX_CONTENT_LENGTH || '9999',
19+
enforceSSL: process.env.ENFORCE_SSL || 'no'
1420
};

favicon.ico

14.7 KB
Binary file not shown.

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,15 @@
4444
"crypto": "0.0.3",
4545
"debug": "^2.6.3",
4646
"express": "^4.15.2",
47+
"express-content-length-validator": "^1.0.0",
48+
"express-enforces-ssl": "^1.1.0",
4749
"express-limiter": "^1.6.0",
4850
"express-validator": "^3.1.2",
4951
"helmet": "^3.6.1",
52+
"hpp": "^0.2.2",
5053
"lodash": "^4.17.4",
5154
"mongoose": "^4.9.0",
55+
"node-rest-client": "^3.1.0",
5256
"q": "^1.4.1",
5357
"randomstring": "^1.1.5",
5458
"redis": "^2.7.1",

routes/index.js

Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,27 @@
11
"use strict";
22
var express = require('express');
33
var router = express.Router();
4-
var bodyParser = require('body-parser');
54
var expressValidator = require('express-validator');
6-
var cors = require('cors');
75
var response = require('../services/response');
86
var encryption = require('../services/encryption');
97
var log = require('../services/logger');
108
var me = require('../package.json');
119
var initialize = require('./initialize');
10+
var config = require('../config');
11+
var helmet = require('helmet');
12+
var client = require('redis').createClient(config.redisURL);
13+
var limiter = require('express-limiter')(router, client);
1214
var _ = require('lodash');
15+
var bodyParser = require('body-parser');
16+
var cors = require('cors');
17+
var hpp = require('hpp');
18+
var contentLength = require('express-content-length-validator');
19+
var MAX_CONTENT_LENGTH_ACCEPTED = config.maxContentLength * 1;
1320

1421
var allRequestData = function(req,res,next){
1522
var requestData = {};
16-
var newRequestData = _.assignIn(requestData, req.params, req.body, req.query);
1723
req.param = function(key, defaultValue){
24+
var newRequestData = _.assignIn(requestData, req.params, req.body, req.query);
1825
if(newRequestData[key]){
1926
return newRequestData[key];
2027
}else if(defaultValue){
@@ -26,49 +33,81 @@ var allRequestData = function(req,res,next){
2633
next();
2734
};
2835

29-
var enforceUserId = function(req,res,next){
36+
var enforceUserIdAndAppId = function(req,res,next){
3037
var userId = req.param('userId');
38+
var appId = req.param('appId');
3139
if(!userId){
3240
res.badRequest(false,'No userId parameter was passed in the payload of this request. Please pass a userId.');
41+
}else if(!appId){
42+
res.badRequest(false,'No appId parameter was passed in the payload of this request. Please pass an appId.');
3343
}else{
34-
// Do a middleware that validates userId here. put the user service endpoint in the env var. ideally, this should be the gateway endpoint
44+
// Do a middleware that validates userId and appID here. put the user service endpoint in the env var. ideally, this should be the gateway endpoint
45+
// Check if this user and app is allowed on this service
46+
req.userId = userId;
47+
req.appId = appId;
3548
next();
3649
}
3750
};
3851

39-
52+
router.use(helmet());
53+
// no client side caching
54+
if(config.noFrontendCaching === 'yes'){
55+
router.use(helmet.noCache());
56+
}
4057
router.use(cors());
41-
router.use(response);
58+
router.options('*', cors());
4259
router.use(bodyParser.urlencoded({ extended: false }));
4360
router.use(bodyParser.json());
4461
router.use(bodyParser.raw());
4562
router.use(bodyParser.text());
63+
router.use(encryption.interpreter);
64+
router.use(hpp());
65+
router.use(contentLength.validateMax({max: MAX_CONTENT_LENGTH_ACCEPTED, status: 400, message: "Stop! Maximum content length exceeded."})); // max size accepted for the content-length
4666
// add the param function to request object
4767
router.use(allRequestData);
48-
// Make userId compolsory in every request
49-
router.use(enforceUserId);
50-
router.use(encryption.interpreter);
51-
router.use(expressValidator());
5268

69+
// API Rate limiter
70+
limiter({
71+
path: '*',
72+
method: 'all',
73+
lookup: ['userId','appId'],
74+
total: config.rateLimit * 1,
75+
expire: config.rateLimitExpiry * 1,
76+
onRateLimited: function (req, res, next) {
77+
next({ message: 'Rate limit exceeded', statusCode: 429 });
78+
}
79+
});
80+
81+
router.use(response);
82+
router.use(expressValidator());
5383
router.use(function(req,res,next){
5484
log.info('[TIME: '+new Date().toISOString()+'] [IP Address: '+req.ip+'] [METHOD: '+req.method+'] [URL: '+req.originalUrl+']');
5585
next();
5686
});
5787

58-
router.options('*', cors());
59-
6088
router.get('/', function (req, res) {
6189
res.ok({name: me.name, version: me.version});
6290
});
6391

64-
router.get('/.well-known/acme-challenge/xvArhQBSilF4V30dGUagNAZ96ASipB0b0ex0kXn0za8', function(req,res){
65-
res.send('xvArhQBSilF4V30dGUagNAZ96ASipB0b0ex0kXn0za8._v6aFbaRYWeOmSebtlD-X4Ixf5tPsyULMsXM8HjsK-Q');
92+
// Let's Encrypt Setup
93+
router.get(config.letsencryptSSLVerificationURL, function(req,res){
94+
res.send(config.letsencryptSSLVerificationBody);
6695
});
6796

68-
// Other routes here
69-
7097
router.use('/', initialize);
7198

99+
// Publicly available routes here
100+
//
101+
//
102+
103+
104+
// Make userId compolsory in every request
105+
router.use(enforceUserIdAndAppId);
106+
107+
// Other routes here
108+
//
109+
//
110+
72111
router.use(function(req, res, next) { // jshint ignore:line
73112
res.notFound();
74113
});

0 commit comments

Comments
 (0)