-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathserver.js
executable file
·183 lines (161 loc) · 6.25 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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
//
// NewsWatcher application
//
// "require" statements to bring in needed Node Modules
if (process.env.NODE_ENV !== 'production') {
require('dotenv').config();
}
if (process.env.USE_SSR === 'TRUE') {
require('ignore-styles')
require("@babel/register")({
ignore: [/(node_module|build|Lambda)/],
presets: ["@babel/preset-env", "@babel/preset-react"],
});
}
// require('newrelic');
var express = require('express'); // For route handlers and templates to serve up.
var path = require('path'); // Populating the path property of the request
var logger = require('morgan'); // HTTP request logging
var responseTime = require('response-time'); // For code timing checks for performance logging
var helmet = require('helmet'); // Helmet module for HTTP header hack mitigations
var rateLimit = require('express-rate-limit'); // IP based rate limiter
const compression = require('compression');
var users = require('./routes/users');
var session = require('./routes/session');
var sharedNews = require('./routes/sharedNews');
var homeNews = require('./routes/homeNews');
var app = express();
app.enable('trust proxy'); // Since we are behind Nginx load balancing with Elastic Beanstalk
app.use(compression());
const limiter = rateLimit({
windowMs: 1 * 60 * 1000, // 1 minutes
max: 2000, // limit each IP address per window
delayMs: 0, // disable delaying - full speed until the max limit is reached
message: { message: 'You have exceeded the request limit!' },
standardHeaders: false, // Disable return rate limit info in the `RateLimit-*` headers
legacyHeaders: false, // Disable the `X-RateLimit-*` headers
skip: (req) => {
// Return true to skip the rate limit testing, or false to proceed with limiting
// We are using the ApiZapi.com load testing tool to test NewsWatcher and do not want to be rate limited for all our own calls
// So we have added a special header value that we can check for and by pass the rate limiting!
// This is because traffic could come from just a few IP addresses
if (req.headers['x-skip-rl-code'] === process.env.SKIP_RATE_LIMIT_CODE) {
return true;
}
}
})
app.use(limiter);
app.use(
helmet({
contentSecurityPolicy: {
useDefaults: true,
directives: {
"default-src": ["'self'"],
"script-src": ["'self'", "'unsafe-inline'", 'ajax.googleapis.com', 'maxcdn.bootstrapcdn.com'],
"style-src": ["'self'", "'unsafe-inline'", 'maxcdn.bootstrapcdn.com'],
"font-src": ["'self'", 'maxcdn.bootstrapcdn.com'],
"img-src": ["'self'", 'https://static01.nyt.com/', 'data:']
// reportUri: '/report-violation',
},
},
crossOriginEmbedderPolicy: false
})
);
// Adds an X-Response-Time header to responses to measure response times
app.use(responseTime());
// logs all HTTP requests. The "dev" option gives it a specific styling
app.use(logger('dev'));
// Sets up the response object in routes to contain a body property with an object of what is parsed from a JSON body request payload
// There is no need for allowing a huge body, it might be some type of attack, so use the limit option
// app.use(express.json({limit: '100kb'}));
app.use(express.json())
// app.get('/apizapiverify.txt', function (req, res) {
// res.sendFile(path.join(__dirname, 'apizapiverify.txt'));
// });
//
// MongoDB database connection initialization
//
var db = {};
var MongoClient = require('mongodb').MongoClient;
//Use connect method to connect to the Server
MongoClient.connect(process.env.MONGODB_CONNECT_URL, { useNewUrlParser: true, useUnifiedTopology: true, minPoolSize: 10, maxPoolSize: 100 }, function (err, client) {
if (err === undefined || err === null) {
db.client = client;
db.collection = client.db('newswatcherdb').collection('newswatcher');
console.log("Connected to MongoDB server");
} else {
console.log("Failed to connected to MongoDB server");
console.log(err);
process.exit(0);
}
});
// Set the database connection for middleware usage
app.use(function (req, res, next) {
req.db = db;
next();
});
if (process.env.USE_SSR === 'TRUE') {
const SSRRender = require('./ssrRender');
app.use("^/$", SSRRender);
app.use(express.static(path.join(__dirname, 'build')));
} else {
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
// Simplifies the serving up of static content such as HTML for the React SPA, images, CSS files, and JavaScript files
app.use(express.static(path.join(__dirname, 'build')));
}
// If our process is shut down, close out the database connections gracefully
process.on('SIGINT', function () {
console.log('MongoDB connection close on app termination');
db.client.close();
process.exit(0);
});
process.on('SIGUSR2', function () {
console.log('MongoDB connection close on app restart');
db.client.close();
process.kill(process.pid, 'SIGUSR2');
});
//
// Rest API routes
app.use('/api/users', users);
app.use('/api/sessions', session);
app.use('/api/sharednews', sharedNews);
app.use('/api/homenews', homeNews);
app.get('/heartbeat', function (req, res) {
res.status(200).json({
uptime: process.uptime(),
message: 'OK',
timestamp: Date.now()
})
});
// catch 404 and forward to error handler
app.use(function (req, res, next) {
let err = new Error('Not Found');
err.status = 404;
next(err);
});
if (app.get('env') === 'development') {
app.use(function (err, req, res, next) { // eslint-disable-line no-unused-vars
if (err.status)
res.status(err.status).json({ message: err.toString(), error: err });
else
res.status(500).json({ message: err.toString(), error: err });
console.log(err);
});
}
app.use(function (err, req, res, next) { // eslint-disable-line no-unused-vars
console.log(err);
if (err.status)
res.status(err.status).json({ message: err.toString(), error: {} });
else
res.status(500).json({ message: err.toString(), error: {} });
});
app.set('port', process.env.PORT || 3000);
var server = app.listen(app.get('port'), function () {
server.keepAliveTimeout = 65000; // TODO: Need this in here according to articles to be greater than the ALB timeout of 60K
console.log('Express server listening on port ' + server.address().port);
});
server.db = db;
console.log(`Worker ${process.pid} started`);
module.exports = server;