mirror of https://gitgud.io/fatchan/jschan.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
135 lines
3.3 KiB
135 lines
3.3 KiB
'use strict';
|
|
|
|
process
|
|
.on('uncaughtException', console.error)
|
|
.on('unhandledRejection', console.error);
|
|
|
|
const express = require('express')
|
|
, session = require('express-session')
|
|
, MongoStore = require('connect-mongo')(session)
|
|
, path = require('path')
|
|
, app = express()
|
|
, bodyParser = require('body-parser')
|
|
, cookieParser = require('cookie-parser')
|
|
, configs = require(__dirname+'/configs/main.json')
|
|
, refererRegex = new RegExp(configs.refererRegex)
|
|
, Mongo = require(__dirname+'/db/db.js')
|
|
, { createHash, randomBytes } = require('crypto');
|
|
|
|
(async () => {
|
|
|
|
console.log('Starting in mode:', process.env.NODE_ENV);
|
|
|
|
// let db connect
|
|
console.log('connecting to db');
|
|
await Mongo.connect();
|
|
|
|
// disable useless express header
|
|
app.disable('x-powered-by');
|
|
|
|
// parse forms
|
|
app.use(bodyParser.urlencoded({extended: true}));
|
|
app.use(bodyParser.json());
|
|
|
|
//parse cookies
|
|
app.use(cookieParser());
|
|
|
|
// session store
|
|
app.use(session({
|
|
secret: configs.sessionSecret,
|
|
store: new MongoStore({ db: Mongo.client.db('sessions') }),
|
|
resave: false,
|
|
saveUninitialized: false,
|
|
cookie: {
|
|
httpOnly: true,
|
|
secure: true,
|
|
sameSite: 'strict',
|
|
}
|
|
}));
|
|
|
|
//trust proxy for nginx
|
|
app.set('trust proxy', 1);
|
|
|
|
//referer header check
|
|
app.use((req, res, next) => {
|
|
const ip = req.headers['x-real-ip'] || req.connection.remoteAddress
|
|
const ipHash = createHash('sha256').update(configs.ipHashSecret + ip).digest('base64');
|
|
res.locals.ip = ipHash;
|
|
if (req.method !== 'POST') {
|
|
return next();
|
|
}
|
|
if (configs.refererCheck === true && (!req.headers.referer || !req.headers.referer.match(refererRegex))) {
|
|
return res.status(403).render('message', {
|
|
'title': 'Forbidden',
|
|
'message': 'Invalid or missing "Referer" header. Are you posting from the correct URL?'
|
|
});
|
|
}
|
|
next();
|
|
})
|
|
|
|
// use pug view engine
|
|
app.set('view engine', 'pug');
|
|
app.set('views', path.join(__dirname, 'views/pages'));
|
|
if (configs.cacheTemplates === true) {
|
|
app.enable('view cache');
|
|
}
|
|
|
|
// routes
|
|
app.use('/forms', require(__dirname+'/controllers/forms.js'));
|
|
app.use('/', require(__dirname+'/controllers/pages.js'));
|
|
|
|
//404 catchall
|
|
app.get('*', (req, res) => {
|
|
res.status(404).render('404');
|
|
})
|
|
|
|
// catch any unhandled errors
|
|
app.use((err, req, res, next) => {
|
|
if (err.code === 'EBADCSRFTOKEN') {
|
|
return res.status(403).send('Invalid CSRF token');
|
|
}
|
|
console.error(err.stack);
|
|
return res.status(500).render('message', {
|
|
'title': 'Internal Server Error',
|
|
'redirect': req.headers.referer || '/'
|
|
});
|
|
})
|
|
|
|
// listen
|
|
const server = app.listen(configs.port, '127.0.0.1', () => {
|
|
|
|
console.log(`listening on port ${configs.port}`);
|
|
|
|
//let PM2 know that this is ready (for graceful reloads)
|
|
if (typeof process.send === 'function') { //make sure we are a child process
|
|
console.info('sending ready signal to PM2');
|
|
process.send('ready');
|
|
}
|
|
|
|
});
|
|
|
|
process.on('SIGINT', () => {
|
|
|
|
console.info('SIGINT signal received');
|
|
|
|
// Stops the server from accepting new connections and finishes existing connections.
|
|
server.close((err) => {
|
|
|
|
// if error, log and exit with error (1 code)
|
|
console.info('closing http server');
|
|
if (err) {
|
|
console.error(err);
|
|
process.exit(1);
|
|
}
|
|
|
|
// close database connection
|
|
console.info('closing db connection');
|
|
Mongo.client.close();
|
|
|
|
// now close without error
|
|
process.exit(0);
|
|
|
|
})
|
|
})
|
|
|
|
})();
|
|
|