forked from Hackbyrd/express-master-boilerplate
-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.js
143 lines (114 loc) · 4.76 KB
/
server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/**
* Main Express Application: set up express app
*/
'use strict';
// require third-party node modules
const express = require('express');
const RateLimit = require("express-rate-limit"); // https://www.npmjs.com/package/express-rate-limit
const RedisStore = require('rate-limit-redis'); // https://www.npmjs.com/package/rate-limit-redis
const sslRedirect = require('heroku-ssl-redirect');
const compression = require('compression');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const passport = require('passport');
const helmet = require('helmet');
const morgan = require('morgan'); // logging: https://github.com/expressjs/morgan
const http = require('http');
const cors = require('cors'); // handle cors
const i18n = require('i18n'); // set up language
// env variables
const {
NODE_ENV,
REDIS_URL,
RATE_LIMIT_WINDOW_MS,
RATE_LIMIT_MAX_PER_WINDOW
} = process.env;
// helpers
const { LOCALES } = require('./helpers/constants');
// server
function server() {
// require custom
const cfgPassport = require('./services/passport'); // configuration for passport
// require custom middleware
const args = require('./middleware/args');
const auth = require('./middleware/auth');
const exit = require('./middleware/exit');
const error = require('./middleware/error');
// set up express app
const app = express();
const newServer = http.createServer(app);
const io = require('socket.io')(newServer); // socket.io
// set up redis with socket
const redis = require('socket.io-redis');
const socket = require('./services/socket'); // require socket service to initiate socket.io
io.adapter(redis(REDIS_URL));
// enable ssl redirect in production
app.use(sslRedirect.default()); // !! dont know why we need a default here
// need to enable this in production because Heroku uses a reverse proxy
if (NODE_ENV === 'production')
app.set('trust proxy', 1); // get ip address using req.ip
// set a rate limit for incoming requests
const limiter = RateLimit({
windowMs: RATE_LIMIT_WINDOW_MS, // 5 minutes
max: RATE_LIMIT_MAX_PER_WINDOW, // limit each IP to 300 requests per windowMs
store: new RedisStore({
redisURL: REDIS_URL
})
});
// set rate limiter
app.use(limiter);
// log requests using morgan, don't log in test env
if (NODE_ENV !== 'test')
app.use(morgan('dev')); // combined, common, dev, short, tiny
// add middleware and they must be in order
app.use(compression()); // GZIP all assets
app.use(cors()); // handle cors
app.use(helmet()); // protect against vulnerabilities
// app.use(rawBody); // adds rawBody to req object
// set up language
i18n.configure({
locales: LOCALES, // set the languages here
defaultLocale: LOCALES[0], // default is the first index
queryParameter: 'lang', // query parameter to switch locale (ie. /home?lang=ch) - defaults to NULL
cookie: 'i18n-locale', // if you change cookie name, you must also change in verifyJWTAuth res.cookie
directory: __dirname + '/locales'
// objectNotation: true // hierarchical translation catalogs. To enable this feature, be sure to set objectNotation to true
});
// you will need to use cookieParser to expose cookies to req.cookies
app.use(cookieParser());
// i18n init parses req for language headers, cookies, etc.
// NOTE: If user is logged in, locale is set in verifyJWTAuth method
app.use(i18n.init);
// save raw body
function rawBodySaver(req, res, buf, encoding) {
if (buf && buf.length)
req.rawBody = buf.toString(encoding || 'utf8');
}
// body parser
app.use(bodyParser.json({ limit: '32mb', verify: rawBodySaver })); // raw application/json
app.use(bodyParser.urlencoded({ limit: '32mb', verify: rawBodySaver, extended: false })); // application/x-www-form-urlencoded
// NOTE: take this out because it interferes with multer
// app.use(bodyParser.raw({ limit: '32mb', verify: rawBodySaver, type: () => true }));
// passport config, must be in this order!
app.use(passport.initialize());
cfgPassport(passport); // set up passport
// custom middleware
app.use(exit.middleware); // stops here if server is in the middle of shutting down
app.use(args.attach); // set req.args
// authentication middleware via passport
app.use(auth.attachJWTAuth(passport));
app.use(auth.JWTAuth);
app.use(auth.verifyJWTAuth);
// host public files
// app.use(express.static(__dirname + '/public'));
// set up routes
const router = require('./routes')(passport); // grab routes
app.use('/', router); // place routes here
// error middleware MUST GO LAST
app.use(error);
// io connection, call socket.connect
io.on('connection', socket.connect);
// return newServer
return newServer;
}
module.exports = server(); // return server app for testing