-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.js
More file actions
151 lines (132 loc) · 4.39 KB
/
Copy pathapp.js
File metadata and controls
151 lines (132 loc) · 4.39 KB
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
// Builds and exports the Express application: security, database readiness,
// sessions, shared view data, routes, and final 404/error handling.
require('dotenv').config();
const express = require('express');
const morgan = require('morgan');
const mongoose = require('mongoose');
const session = require('express-session');
const MongoStore = require('connect-mongo');
const flash = require('connect-flash');
const path = require('path');
const helmet = require('helmet');
const compression = require('compression');
const { verifySameOrigin } = require('./middlewares');
const User = require('./models/user');
const app = express();
const isProd = process.env.NODE_ENV === 'production';
const requiredEnvironment = [
'MONGODB_URI',
'SECRET_KEY',
'CLOUDINARY_CLOUD_NAME',
'CLOUDINARY_API_KEY',
'CLOUDINARY_API_SECRET'
];
const missingEnvironment = requiredEnvironment.filter(name => !process.env[name]);
if (missingEnvironment.length) {
throw new Error(`Missing required environment variables: ${missingEnvironment.join(', ')}`);
}
// EJS views and public assets.
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
// Baseline HTTP security and response compression.
app.use(helmet({
contentSecurityPolicy: false,
crossOriginResourcePolicy: { policy: 'cross-origin' }
}));
app.use(compression());
//static
app.use(express.static(path.join(__dirname, 'public')));
//parsers & logging
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(morgan(isProd ? 'combined' : 'dev'));
// Share one connection promise so local and serverless entry points wait for MongoDB.
const dbURI = process.env.MONGODB_URI;
const databaseReady = mongoose.connect(dbURI)
.then(() => {
console.log('Connected to MongoDB Atlas');
return mongoose.connection;
});
// Attach a handler immediately so serverless cold starts cannot emit an unhandled rejection.
databaseReady.catch(() => {});
app.databaseReady = databaseReady;
app.use(async (req, res, next) => {
try {
await databaseReady;
next();
} catch (err) {
next(err);
}
});
// Persist authenticated sessions in MongoDB rather than process memory.
if (isProd) app.set('trust proxy', 1);
const ONE_HOUR_MS = 60 * 60 * 1000;
app.use(session({
name: 'sid',
secret: process.env.SECRET_KEY,
resave: false,
saveUninitialized: false,
rolling: true,
cookie: {
maxAge: ONE_HOUR_MS,
httpOnly: true,
secure: isProd,
sameSite: isProd ? 'lax' : 'lax'
},
store: MongoStore.create({
mongoUrl: dbURI,
ttl: Math.floor(ONE_HOUR_MS / 1000),
touchAfter: 15 * 60
})
}));
app.use(flash());
// Resolve the current user once per request and expose common template locals.
app.use(async (req, res, next) => {
if (req.session.userId) {
try {
const user = await User.findById(req.session.userId);
if (!user) delete req.session.userId;
req.user = user || null;
res.locals.user = user || null;
} catch (err) {
return next(err);
}
} else {
req.user = null;
res.locals.user = null;
}
res.locals.successMessages = req.flash('success');
res.locals.errorMessages = req.flash('error');
next();
});
// Reject cross-origin mutations after session/user context has been prepared.
app.use(verifySameOrigin);
//routes
const mainRoutes = require('./routes/mainRoutes');
const eventRoutes = require('./routes/eventRoutes');
const userRoutes = require('./routes/userRoutes');
app.use('/', mainRoutes);
app.use('/events', eventRoutes);
app.use('/user', userRoutes);
//404 (before error handler)
app.use((req, res) => {
res.status(404).render('error', {
errorCode: 404,
errorTitle: 'Page Not Found',
errorMessage: 'The page you are looking for does not exist.'
});
});
//error handler
app.use((err, req, res, next) => {
console.error('Unhandled error:', err);
if (res.headersSent) return next(err);
res.locals.user ??= null;
res.locals.successMessages ??= [];
res.locals.errorMessages ??= [];
res.status(err.status || 500).render('error', {
errorCode: err.status || 500,
errorTitle: 'Internal Server Error',
errorMessage: isProd ? 'An unexpected error occurred.' : (err.message || 'An unexpected error occurred.')
});
});
module.exports = app;