jschan - Anonymous imageboard software. Classic look, modern features and feel. Works without JavaScript and supports Tor, I2P, Lokinet, etc.
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.

156 lines
4.5 KiB

5 years ago
'use strict';
process
.on('uncaughtException', console.error)
.on('unhandledRejection', console.error);
5 years ago
const express = require('express')
, session = require('express-session')
, redisStore = require('connect-redis')(session)
, path = require('path')
, app = express()
, server = require('http').createServer(app)
5 years ago
, cookieParser = require('cookie-parser')
, { cacheTemplates, boardDefaults, sessionSecret, globalLimits,
secureCookies, debugLogs, ipHashPermLevel, meta, port } = require(__dirname+'/configs/main.js')
, processIp = require(__dirname+'/helpers/processip.js')
, referrerCheck = require(__dirname+'/helpers/referrercheck.js')
, { themes, codeThemes } = require(__dirname+'/helpers/themes.js')
, Mongo = require(__dirname+'/db/db.js')
, Socketio = require(__dirname+'/socketio.js')
, dynamicResponse = require(__dirname+'/helpers/dynamic.js')
, { DAY } = require(__dirname+'/helpers/timeutils.js')
, CachePugTemplates = require('cache-pug-templates');
5 years ago
(async () => {
const env = process.env.NODE_ENV;
const production = env === 'production';
debugLogs && console.log('STARTING IN MODE:', env);
// connect to mongodb
debugLogs && console.log('CONNECTING TO MONGODB');
5 years ago
await Mongo.connect();
// connect to redis
debugLogs && console.log('CONNECTING TO REDIS');
const { redisClient } = require(__dirname+'/redis.js');
5 years ago
// connect socketio
debugLogs && console.log('STARTING WEBSOCKET');
Socketio.connect(server);
// disable useless express header
app.disable('x-powered-by');
// parse forms
app.use(express.urlencoded({extended: false}));
//app.use(express.json()); //unused atm, will be used with forms.js eventually
// parse cookies
app.use(cookieParser());
5 years ago
// session store
app.use(session({
secret: sessionSecret,
store: new redisStore({
client: redisClient,
}),
5 years ago
resave: false,
saveUninitialized: false,
rolling: true,
cookie: {
httpOnly: true,
secure: secureCookies && production,
sameSite: 'strict',
maxAge: DAY,
}
5 years ago
}));
//trust proxy for nginx
app.set('trust proxy', 1);
5 years ago
//self explanatory middlewares
app.use(processIp);
app.use(referrerCheck);
5 years ago
// use pug view engine
const views = path.join(__dirname, 'views/pages');
5 years ago
app.set('view engine', 'pug');
app.set('views', views);
//cache loaded templates
if (cacheTemplates === true) {
app.enable('view cache');
}
5 years ago
//default settings
app.locals.defaultTheme = boardDefaults.theme;
app.locals.defaultCodeTheme = boardDefaults.codeTheme;
app.locals.globalLimits = globalLimits;
app.locals.ipHashPermLevel = ipHashPermLevel;
app.locals.meta = meta;
5 years ago
// routes
if (!production) {
app.use(express.static(__dirname+'/static'));
app.use(express.static(__dirname+'/static/html'));
app.use(express.static(__dirname+'/static/json'));
}
app.use('/forms', require(__dirname+'/controllers/forms.js'));
app.use('/', require(__dirname+'/controllers/pages.js'));
5 years ago
//404 catchall
5 years ago
app.get('*', (req, res) => {
res.status(404).render('404');
5 years ago
})
// catch any unhandled errors
5 years ago
app.use((err, req, res, next) => {
if (err.code === 'EBADCSRFTOKEN') {
return res.status(403).render('message', {
'title': 'Forbidden',
'message': 'Invalid CSRF token'
});
5 years ago
}
console.error(err);
return dynamicResponse(req, res, 500, 'message', {
'title': 'Internal Server Error',
'error': 'Internal Server Error', //what to put here?
'redirect': req.headers.referer || '/'
});
5 years ago
})
//listen
server.listen(port, '127.0.0.1', () => {
new CachePugTemplates({ app, views }).start();
debugLogs && console.log(`LISTENING ON :${port}`);
//let PM2 know that this is ready for graceful reloads and to serialise startup
if (typeof process.send === 'function') {
//make sure we are a child process of PM2 i.e. not in dev
debugLogs && console.log('SENT READY SIGNAL TO PM2');
process.send('ready');
}
});
//listen for sigint from PM2
process.on('SIGINT', () => {
debugLogs && console.log('SIGINT SIGNAL RECEIVED');
// Stops the server from accepting new connections and finishes existing connections.
Socketio.io.close((err) => {
// if error, log and exit with error (1 code)
debugLogs && console.log('CLOSING SERVER');
if (err) {
console.error(err);
process.exit(1);
}
// close database connection
debugLogs && console.log('DISCONNECTING MONGODB');
Mongo.client.close();
//close redis connection
debugLogs && console.log('DISCONNECTING REDIS')
redisClient.quit();
// now close without error
process.exit(0);
});
});
5 years ago
})();