organize middlewares

removed app.locals.middleware
middlewares can be required anywhere, ie in controllers
v1.18.x
barisusakli 9 years ago
parent f5941cbf1c
commit 8f408faf46

@ -376,8 +376,8 @@ Controllers.handle404 = function(req, res) {
if (res.locals.isAPI) {
return res.json({path: validator.escape(path.replace(/^\/api/, '')), title: '[[global:404.title]]'});
}
req.app.locals.middleware.buildHeader(req, res, function() {
var middleware = require('../middleware');
middleware.buildHeader(req, res, function() {
res.render('404', {path: validator.escape(path), title: '[[global:404.title]]'});
});
} else {
@ -402,7 +402,8 @@ Controllers.handleURIErrors = function(err, req, res, next) {
error: '[[global:400.title]]'
});
} else {
req.app.locals.middleware.buildHeader(req, res, function() {
var middleware = require('../middleware');
middleware.buildHeader(req, res, function() {
res.render('400', { error: validator.escape(String(err.message)) });
});
}
@ -435,7 +436,8 @@ Controllers.handleErrors = function(err, req, res, next) {
if (res.locals.isAPI) {
res.json({path: validator.escape(path), error: err.message});
} else {
req.app.locals.middleware.buildHeader(req, res, function() {
var middleware = require('../middleware');
middleware.buildHeader(req, res, function() {
res.render('500', { path: validator.escape(path), error: validator.escape(String(err.message)) });
});
}

@ -1,11 +1,12 @@
'use strict';
var winston = require('winston'),
db = require('../database'),
pubsub = require('../pubsub'),
nconf = require('nconf'),
utils = require('../../public/src/utils');
var winston = require('winston');
var nconf = require('nconf');
var db = require('../database');
var pubsub = require('../pubsub');
var utils = require('../../public/src/utils');
module.exports = function(Meta) {

@ -1,130 +1,125 @@
"use strict";
var app,
middleware = {},
nconf = require('nconf'),
async = require('async'),
winston = require('winston'),
user = require('../user'),
meta = require('../meta'),
plugins = require('../plugins'),
controllers = {
api: require('../controllers/api'),
helpers: require('../controllers/helpers')
};
middleware.isAdmin = function(req, res, next) {
winston.warn('[middleware.admin.isAdmin] deprecation warning, no need to use this from plugins!');
if (!req.user) {
return controllers.helpers.notAllowed(req, res);
}
user.isAdministrator(req.user.uid, function (err, isAdmin) {
if (err || isAdmin) {
return next(err);
}
controllers.helpers.notAllowed(req, res);
});
var async = require('async');
var winston = require('winston');
var user = require('../user');
var meta = require('../meta');
var plugins = require('../plugins');
var controllers = {
api: require('../controllers/api'),
helpers: require('../controllers/helpers')
};
middleware.buildHeader = function(req, res, next) {
res.locals.renderAdminHeader = true;
module.exports = function(middleware) {
middleware.admin = {};
middleware.admin.isAdmin = function(req, res, next) {
winston.warn('[middleware.admin.isAdmin] deprecation warning, no need to use this from plugins!');
async.parallel({
config: function(next) {
controllers.api.getConfig(req, res, next);
},
footer: function(next) {
app.render('admin/footer', {}, next);
}
}, function(err, results) {
if (err) {
return next(err);
if (!req.user) {
return controllers.helpers.notAllowed(req, res);
}
res.locals.config = results.config;
res.locals.adminFooter = results.footer;
next();
});
};
user.isAdministrator(req.user.uid, function (err, isAdmin) {
if (err || isAdmin) {
return next(err);
}
middleware.renderHeader = function(req, res, data, next) {
var custom_header = {
'plugins': [],
'authentication': []
controllers.helpers.notAllowed(req, res);
});
};
user.getUserFields(req.uid, ['username', 'userslug', 'email', 'picture', 'email:confirmed'], function(err, userData) {
if (err) {
return next(err);
}
userData.uid = req.uid;
userData['email:confirmed'] = parseInt(userData['email:confirmed'], 10) === 1;
middleware.admin.buildHeader = function(req, res, next) {
res.locals.renderAdminHeader = true;
async.parallel({
scripts: function(next) {
plugins.fireHook('filter:admin.scripts.get', [], function(err, scripts) {
if (err) {
return next(err);
}
var arr = [];
scripts.forEach(function(script) {
arr.push({src: script});
});
next(null, arr);
});
},
custom_header: function(next) {
plugins.fireHook('filter:admin.header.build', custom_header, next);
},
config: function(next) {
controllers.api.getConfig(req, res, next);
},
configs: function(next) {
meta.configs.list(next);
footer: function(next) {
req.app.render('admin/footer', {}, next);
}
}, function(err, results) {
if (err) {
return next(err);
}
res.locals.config = results.config;
res.locals.adminFooter = results.footer;
next();
});
};
middleware.admin.renderHeader = function(req, res, data, next) {
var custom_header = {
'plugins': [],
'authentication': []
};
var acpPath = req.path.slice(1).split('/');
acpPath.forEach(function(path, i) {
acpPath[i] = path.charAt(0).toUpperCase() + path.slice(1);
user.getUserFields(req.uid, ['username', 'userslug', 'email', 'picture', 'email:confirmed'], function(err, userData) {
if (err) {
return next(err);
}
userData.uid = req.uid;
userData['email:confirmed'] = parseInt(userData['email:confirmed'], 10) === 1;
async.parallel({
scripts: function(next) {
plugins.fireHook('filter:admin.scripts.get', [], function(err, scripts) {
if (err) {
return next(err);
}
var arr = [];
scripts.forEach(function(script) {
arr.push({src: script});
});
next(null, arr);
});
},
custom_header: function(next) {
plugins.fireHook('filter:admin.header.build', custom_header, next);
},
config: function(next) {
controllers.api.getConfig(req, res, next);
},
configs: function(next) {
meta.configs.list(next);
}
}, function(err, results) {
if (err) {
return next(err);
}
res.locals.config = results.config;
var acpPath = req.path.slice(1).split('/');
acpPath.forEach(function(path, i) {
acpPath[i] = path.charAt(0).toUpperCase() + path.slice(1);
});
acpPath = acpPath.join(' > ');
var templateValues = {
config: results.config,
configJSON: JSON.stringify(results.config),
relative_path: results.config.relative_path,
adminConfigJSON: encodeURIComponent(JSON.stringify(results.configs)),
user: userData,
userJSON: JSON.stringify(userData).replace(/'/g, "\\'"),
plugins: results.custom_header.plugins,
authentication: results.custom_header.authentication,
scripts: results.scripts,
'cache-buster': meta.config['cache-buster'] ? 'v=' + meta.config['cache-buster'] : '',
env: process.env.NODE_ENV ? true : false,
title: (acpPath || 'Dashboard') + ' | NodeBB Admin Control Panel',
bodyClass: data.bodyClass
};
templateValues.template = {name: res.locals.template};
templateValues.template[res.locals.template] = true;
req.app.render('admin/header', templateValues, next);
});
acpPath = acpPath.join(' > ');
var templateValues = {
config: results.config,
configJSON: JSON.stringify(results.config),
relative_path: results.config.relative_path,
adminConfigJSON: encodeURIComponent(JSON.stringify(results.configs)),
user: userData,
userJSON: JSON.stringify(userData).replace(/'/g, "\\'"),
plugins: results.custom_header.plugins,
authentication: results.custom_header.authentication,
scripts: results.scripts,
'cache-buster': meta.config['cache-buster'] ? 'v=' + meta.config['cache-buster'] : '',
env: process.env.NODE_ENV ? true : false,
title: (acpPath || 'Dashboard') + ' | NodeBB Admin Control Panel',
bodyClass: data.bodyClass
};
templateValues.template = {name: res.locals.template};
templateValues.template[res.locals.template] = true;
app.render('admin/header', templateValues, next);
});
});
};
module.exports = function(webserver) {
app = webserver;
return middleware;
};
};

@ -16,7 +16,7 @@ var controllers = {
helpers: require('../controllers/helpers')
};
module.exports = function(app, middleware) {
module.exports = function(middleware) {
middleware.buildHeader = function(req, res, next) {
res.locals.renderHeader = true;
@ -28,7 +28,7 @@ module.exports = function(app, middleware) {
controllers.api.getConfig(req, res, next);
},
footer: function(next) {
app.render('footer', {
req.app.render('footer', {
loggedIn: !!req.uid,
title: validator.escape(meta.config.title || meta.config.browserTitle || 'NodeBB')
}, next);
@ -160,7 +160,7 @@ module.exports = function(app, middleware) {
return callback(err);
}
app.render('header', data.templateValues, callback);
req.app.render('header', data.templateValues, callback);
});
});
};

@ -0,0 +1,51 @@
'use strict';
var meta = require('../meta');
var _ = require('underscore');
module.exports = function(middleware) {
middleware.addHeaders = function (req, res, next) {
var defaults = {
'X-Powered-By': 'NodeBB',
'X-Frame-Options': 'SAMEORIGIN',
'Access-Control-Allow-Origin': 'null' // yes, string null.
};
var headers = {
'X-Powered-By': meta.config['powered-by'],
'X-Frame-Options': meta.config['allow-from-uri'] ? 'ALLOW-FROM ' + meta.config['allow-from-uri'] : undefined,
'Access-Control-Allow-Origin': meta.config['access-control-allow-origin'],
'Access-Control-Allow-Methods': meta.config['access-control-allow-methods'],
'Access-Control-Allow-Headers': meta.config['access-control-allow-headers']
};
_.defaults(headers, defaults);
headers = _.pick(headers, Boolean); // Remove falsy headers
for(var key in headers) {
if (headers.hasOwnProperty(key)) {
res.setHeader(key, headers[key]);
}
}
next();
};
middleware.addExpiresHeaders = function(req, res, next) {
if (req.app.enabled('cache')) {
res.setHeader("Cache-Control", "public, max-age=5184000");
res.setHeader("Expires", new Date(Date.now() + 5184000000).toUTCString());
} else {
res.setHeader("Cache-Control", "public, max-age=0");
res.setHeader("Expires", new Date().toUTCString());
}
next();
};
};

@ -1,83 +1,202 @@
"use strict";
var meta = require('../meta'),
db = require('../database'),
file = require('../file'),
auth = require('../routes/authentication'),
path = require('path'),
nconf = require('nconf'),
flash = require('connect-flash'),
templates = require('templates.js'),
bodyParser = require('body-parser'),
cookieParser = require('cookie-parser'),
compression = require('compression'),
favicon = require('serve-favicon'),
session = require('express-session'),
useragent = require('express-useragent');
var async = require('async');
var fs = require('fs');
var path = require('path');
var csrf = require('csurf');
var validator = require('validator');
var nconf = require('nconf');
var ensureLoggedIn = require('connect-ensure-login');
var toobusy = require('toobusy-js');
var plugins = require('../plugins');
var languages = require('../languages');
var meta = require('../meta');
var user = require('../user');
var groups = require('../groups');
var analytics = require('../analytics');
var controllers = {
api: require('./../controllers/api'),
helpers: require('../controllers/helpers')
};
var middleware = {};
function setupFavicon(app) {
var faviconPath = path.join(__dirname, '../../', 'public', meta.config['brand:favicon'] ? meta.config['brand:favicon'] : 'favicon.ico');
if (file.existsSync(faviconPath)) {
app.use(nconf.get('relative_path'), favicon(faviconPath));
middleware.applyCSRF = csrf();
middleware.ensureLoggedIn = ensureLoggedIn.ensureLoggedIn(nconf.get('relative_path') + '/login');
require('./admin')(middleware);
require('./header')(middleware);
require('./render')(middleware);
require('./maintenance')(middleware);
require('./user')(middleware);
require('./headers')(middleware);
middleware.authenticate = function(req, res, next) {
if (req.user) {
return next();
} else if (plugins.hasListeners('action:middleware.authenticate')) {
return plugins.fireHook('action:middleware.authenticate', {
req: req,
res: res,
next: next
});
}
}
module.exports = function(app) {
var relativePath = nconf.get('relative_path');
controllers.helpers.notAllowed(req, res);
};
middleware = require('./middleware')(app);
middleware.pageView = function(req, res, next) {
analytics.pageView({
ip: req.ip,
path: req.path,
uid: req.hasOwnProperty('user') && req.user.hasOwnProperty('uid') ? parseInt(req.user.uid, 10) : 0
});
plugins.fireHook('action:middleware.pageView', {req: req});
if (req.user) {
user.updateLastOnlineTime(req.user.uid);
if (req.path.startsWith('/api/users') || req.path.startsWith('/users')) {
user.updateOnlineUsers(req.user.uid, next);
} else {
user.updateOnlineUsers(req.user.uid);
next();
}
} else {
next();
}
};
app.engine('tpl', templates.__express);
app.set('view engine', 'tpl');
app.set('views', nconf.get('views_dir'));
app.set('json spaces', process.env.NODE_ENV === 'development' ? 4 : 0);
app.use(flash());
app.enable('view cache');
middleware.pluginHooks = function(req, res, next) {
async.each(plugins.loadedHooks['filter:router.page'] || [], function(hookObj, next) {
hookObj.method(req, res, next);
}, function() {
// If it got here, then none of the subscribed hooks did anything, or there were no hooks
next();
});
};
app.use(compression());
middleware.validateFiles = function(req, res, next) {
if (!Array.isArray(req.files.files) || !req.files.files.length) {
return next(new Error(['[[error:invalid-files]]']));
}
setupFavicon(app);
next();
};
app.use(relativePath + '/apple-touch-icon', middleware.routeTouchIcon);
middleware.prepareAPI = function(req, res, next) {
res.locals.isAPI = true;
next();
};
middleware.routeTouchIcon = function(req, res) {
if (meta.config['brand:touchIcon'] && validator.isURL(meta.config['brand:touchIcon'])) {
return res.redirect(meta.config['brand:touchIcon']);
} else {
return res.sendFile(path.join(__dirname, '../../public', meta.config['brand:touchIcon'] || '/logo.png'), {
maxAge: req.app.enabled('cache') ? 5184000000 : 0
});
}
};
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.use(cookieParser());
app.use(useragent.express());
middleware.privateTagListing = function(req, res, next) {
if (!req.user && parseInt(meta.config.privateTagListing, 10) === 1) {
controllers.helpers.notAllowed(req, res);
} else {
next();
}
};
var cookie = {
maxAge: 1000 * 60 * 60 * 24 * (parseInt(meta.config.loginDays, 10) || 14)
};
middleware.exposeGroupName = function(req, res, next) {
expose('groupName', groups.getGroupNameByGroupSlug, 'slug', req, res, next);
};
if (meta.config.cookieDomain) {
cookie.domain = meta.config.cookieDomain;
middleware.exposeUid = function(req, res, next) {
expose('uid', user.getUidByUserslug, 'userslug', req, res, next);
};
function expose(exposedField, method, field, req, res, next) {
if (!req.params.hasOwnProperty(field)) {
return next();
}
method(req.params[field], function(err, id) {
if (err) {
return next(err);
}
res.locals[exposedField] = id;
next();
});
}
middleware.privateUploads = function(req, res, next) {
if (req.user || parseInt(meta.config.privateUploads, 10) !== 1) {
return next();
}
if (req.path.startsWith('/uploads/files')) {
return res.status(403).json('not-allowed');
}
next();
};
if (nconf.get('secure')) {
cookie.secure = true;
middleware.busyCheck = function(req, res, next) {
if (global.env === 'production' && (!meta.config.hasOwnProperty('eventLoopCheckEnabled') || parseInt(meta.config.eventLoopCheckEnabled, 10) === 1) && toobusy()) {
analytics.increment('errors:503');
res.status(503).type('text/html').sendFile(path.join(__dirname, '../../public/503.html'));
} else {
next();
}
};
middleware.applyBlacklist = function(req, res, next) {
meta.blacklist.test(req.ip, function(err) {
next(err);
});
};
middleware.processLanguages = function(req, res, next) {
var code = req.params.code;
var key = req.path.match(/[\w]+\.json/);
if (relativePath !== '') {
cookie.path = relativePath;
if (code && key) {
languages.get(code, key[0], function(err, language) {
if (err) {
return next(err);
}
res.status(200).json(language);
});
} else {
res.status(404).json('{}');
}
};
app.use(session({
store: db.sessionStore,
secret: nconf.get('secret'),
key: 'express.sid',
cookie: cookie,
resave: true,
saveUninitialized: true
}));
middleware.processTimeagoLocales = function(req, res, next) {
var fallback = req.path.indexOf('-short') === -1 ? 'jquery.timeago.en.js' : 'jquery.timeago.en-short.js',
localPath = path.join(__dirname, '../../public/vendor/jquery/timeago/locales', req.path),
exists;
app.use(middleware.addHeaders);
app.use(middleware.processRender);
auth.initialize(app, middleware);
try {
exists = fs.accessSync(localPath, fs.F_OK | fs.R_OK);
} catch(e) {
exists = false;
}
return middleware;
if (exists) {
res.status(200).sendFile(localPath, {
maxAge: req.app.enabled('cache') ? 5184000000 : 0
});
} else {
res.status(200).sendFile(path.join(__dirname, '../../public/vendor/jquery/timeago/locales', fallback), {
maxAge: req.app.enabled('cache') ? 5184000000 : 0
});
}
};
module.exports = middleware;

@ -1,384 +0,0 @@
"use strict";
var app;
var middleware = {
admin: {}
};
var async = require('async');
var fs = require('fs');
var path = require('path');
var csrf = require('csurf');
var _ = require('underscore');
var validator = require('validator');
var nconf = require('nconf');
var ensureLoggedIn = require('connect-ensure-login');
var toobusy = require('toobusy-js');
var plugins = require('../plugins');
var languages = require('../languages');
var meta = require('../meta');
var user = require('../user');
var groups = require('../groups');
var analytics = require('../analytics');
var controllers = {
api: require('./../controllers/api'),
helpers: require('../controllers/helpers')
};
toobusy.maxLag(parseInt(meta.config.eventLoopLagThreshold, 10) || 100);
toobusy.interval(parseInt(meta.config.eventLoopInterval, 10) || 500);
middleware.authenticate = function(req, res, next) {
if (req.user) {
return next();
} else if (plugins.hasListeners('action:middleware.authenticate')) {
return plugins.fireHook('action:middleware.authenticate', {
req: req,
res: res,
next: next
});
}
controllers.helpers.notAllowed(req, res);
};
middleware.applyCSRF = csrf();
middleware.ensureLoggedIn = ensureLoggedIn.ensureLoggedIn(nconf.get('relative_path') + '/login');
middleware.pageView = function(req, res, next) {
analytics.pageView({
ip: req.ip,
path: req.path,
uid: req.hasOwnProperty('user') && req.user.hasOwnProperty('uid') ? parseInt(req.user.uid, 10) : 0
});
plugins.fireHook('action:middleware.pageView', {req: req});
if (req.user) {
user.updateLastOnlineTime(req.user.uid);
if (req.path.startsWith('/api/users') || req.path.startsWith('/users')) {
user.updateOnlineUsers(req.user.uid, next);
} else {
user.updateOnlineUsers(req.user.uid);
next();
}
} else {
next();
}
};
middleware.addHeaders = function (req, res, next) {
var defaults = {
'X-Powered-By': 'NodeBB',
'X-Frame-Options': 'SAMEORIGIN',
'Access-Control-Allow-Origin': 'null' // yes, string null.
};
var headers = {
'X-Powered-By': meta.config['powered-by'],
'X-Frame-Options': meta.config['allow-from-uri'] ? 'ALLOW-FROM ' + meta.config['allow-from-uri'] : undefined,
'Access-Control-Allow-Origin': meta.config['access-control-allow-origin'],
'Access-Control-Allow-Methods': meta.config['access-control-allow-methods'],
'Access-Control-Allow-Headers': meta.config['access-control-allow-headers']
};
_.defaults(headers, defaults);
headers = _.pick(headers, Boolean); // Remove falsy headers
for(var key in headers) {
if (headers.hasOwnProperty(key)) {
res.setHeader(key, headers[key]);
}
}
next();
};
middleware.pluginHooks = function(req, res, next) {
async.each(plugins.loadedHooks['filter:router.page'] || [], function(hookObj, next) {
hookObj.method(req, res, next);
}, function() {
// If it got here, then none of the subscribed hooks did anything, or there were no hooks
next();
});
};
middleware.redirectToAccountIfLoggedIn = function(req, res, next) {
if (req.session.forceLogin) {
return next();
}
if (!req.user) {
return next();
}
user.getUserField(req.user.uid, 'userslug', function (err, userslug) {
if (err) {
return next(err);
}
controllers.helpers.redirect(res, '/user/' + userslug);
});
};
middleware.validateFiles = function(req, res, next) {
if (!Array.isArray(req.files.files) || !req.files.files.length) {
return next(new Error(['[[error:invalid-files]]']));
}
next();
};
middleware.prepareAPI = function(req, res, next) {
res.locals.isAPI = true;
next();
};
middleware.checkGlobalPrivacySettings = function(req, res, next) {
if (!req.user && !!parseInt(meta.config.privateUserInfo, 10)) {
return controllers.helpers.notAllowed(req, res);
}
next();
};
middleware.checkAccountPermissions = function(req, res, next) {
// This middleware ensures that only the requested user and admins can pass
async.waterfall([
function (next) {
middleware.authenticate(req, res, next);
},
function (next) {
user.getUidByUserslug(req.params.userslug, next);
},
function (uid, next) {
if (parseInt(uid, 10) === req.uid) {
return next(null, true);
}
user.isAdminOrGlobalMod(req.uid, next);
}
], function (err, allowed) {
if (err || allowed) {
return next(err);
}
controllers.helpers.notAllowed(req, res);
});
};
middleware.redirectUidToUserslug = function(req, res, next) {
var uid = parseInt(req.params.uid, 10);
if (!uid) {
return next();
}
user.getUserField(uid, 'userslug', function(err, userslug) {
if (err || !userslug) {
return next(err);
}
var path = req.path.replace(/^\/api/, '')
.replace('uid', 'user')
.replace(uid, function() { return userslug; });
controllers.helpers.redirect(res, path);
});
};
middleware.isAdmin = function(req, res, next) {
if (!req.uid) {
return controllers.helpers.notAllowed(req, res);
}
user.isAdministrator(req.uid, function (err, isAdmin) {
if (err) {
return next(err);
}
if (isAdmin) {
user.hasPassword(req.uid, function(err, hasPassword) {
if (err) {
return next(err);
}
if (!hasPassword) {
return next();
}
var loginTime = req.session.meta ? req.session.meta.datetime : 0;
if (loginTime && parseInt(loginTime, 10) > Date.now() - 3600000) {
var timeLeft = parseInt(loginTime, 10) - (Date.now() - 3600000);
if (timeLeft < 300000) {
req.session.meta.datetime += 300000;
}
return next();
}
req.session.returnTo = req.path.replace(/^\/api/, '');
req.session.forceLogin = 1;
if (res.locals.isAPI) {
res.status(401).json({});
} else {
res.redirect(nconf.get('relative_path') + '/login');
}
});
return;
}
if (res.locals.isAPI) {
return controllers.helpers.notAllowed(req, res);
}
middleware.buildHeader(req, res, function() {
controllers.helpers.notAllowed(req, res);
});
});
};
middleware.routeTouchIcon = function(req, res) {
if (meta.config['brand:touchIcon'] && validator.isURL(meta.config['brand:touchIcon'])) {
return res.redirect(meta.config['brand:touchIcon']);
} else {
return res.sendFile(path.join(__dirname, '../../public', meta.config['brand:touchIcon'] || '/logo.png'), {
maxAge: app.enabled('cache') ? 5184000000 : 0
});
}
};
middleware.addExpiresHeaders = function(req, res, next) {
if (app.enabled('cache')) {
res.setHeader("Cache-Control", "public, max-age=5184000");
res.setHeader("Expires", new Date(Date.now() + 5184000000).toUTCString());
} else {
res.setHeader("Cache-Control", "public, max-age=0");
res.setHeader("Expires", new Date().toUTCString());
}
next();
};
middleware.privateTagListing = function(req, res, next) {
if (!req.user && parseInt(meta.config.privateTagListing, 10) === 1) {
controllers.helpers.notAllowed(req, res);
} else {
next();
}
};
middleware.exposeGroupName = function(req, res, next) {
expose('groupName', groups.getGroupNameByGroupSlug, 'slug', req, res, next);
};
middleware.exposeUid = function(req, res, next) {
expose('uid', user.getUidByUserslug, 'userslug', req, res, next);
};
function expose(exposedField, method, field, req, res, next) {
if (!req.params.hasOwnProperty(field)) {
return next();
}
method(req.params[field], function(err, id) {
if (err) {
return next(err);
}
res.locals[exposedField] = id;
next();
});
}
middleware.requireUser = function(req, res, next) {
if (req.user) {
return next();
}
res.status(403).render('403', {title: '[[global:403.title]]'});
};
middleware.privateUploads = function(req, res, next) {
if (req.user || parseInt(meta.config.privateUploads, 10) !== 1) {
return next();
}
if (req.path.startsWith('/uploads/files')) {
return res.status(403).json('not-allowed');
}
next();
};
middleware.busyCheck = function(req, res, next) {
if (global.env === 'production' && (!meta.config.hasOwnProperty('eventLoopCheckEnabled') || parseInt(meta.config.eventLoopCheckEnabled, 10) === 1) && toobusy()) {
analytics.increment('errors:503');
res.status(503).type('text/html').sendFile(path.join(__dirname, '../../public/503.html'));
} else {
next();
}
};
middleware.applyBlacklist = function(req, res, next) {
meta.blacklist.test(req.ip, function(err) {
next(err);
});
};
middleware.processLanguages = function(req, res, next) {
var code = req.params.code;
var key = req.path.match(/[\w]+\.json/);
if (code && key) {
languages.get(code, key[0], function(err, language) {
if (err) {
return next(err);
}
res.status(200).json(language);
});
} else {
res.status(404).json('{}');
}
};
middleware.processTimeagoLocales = function(req, res, next) {
var fallback = req.path.indexOf('-short') === -1 ? 'jquery.timeago.en.js' : 'jquery.timeago.en-short.js',
localPath = path.join(__dirname, '../../public/vendor/jquery/timeago/locales', req.path),
exists;
try {
exists = fs.accessSync(localPath, fs.F_OK | fs.R_OK);
} catch(e) {
exists = false;
}
if (exists) {
res.status(200).sendFile(localPath, {
maxAge: app.enabled('cache') ? 5184000000 : 0
});
} else {
res.status(200).sendFile(path.join(__dirname, '../../public/vendor/jquery/timeago/locales', fallback), {
maxAge: app.enabled('cache') ? 5184000000 : 0
});
}
};
middleware.registrationComplete = function(req, res, next) {
// If the user's session contains registration data, redirect the user to complete registration
if (!req.session.hasOwnProperty('registration')) {
return next();
} else {
if (!req.path.endsWith('/register/complete')) {
controllers.helpers.redirect(res, '/register/complete');
} else {
return next();
}
}
};
module.exports = function(webserver) {
app = webserver;
middleware.admin = require('./admin')(webserver);
require('./header')(app, middleware);
require('./render')(middleware);
require('./maintenance')(middleware);
return middleware;
};

@ -0,0 +1,154 @@
'use strict';
var async = require('async');
var nconf = require('nconf');
var meta = require('../meta');
var user = require('../user');
var controllers = {
helpers: require('../controllers/helpers')
};
module.exports = function(middleware) {
middleware.checkGlobalPrivacySettings = function(req, res, next) {
if (!req.user && !!parseInt(meta.config.privateUserInfo, 10)) {
return controllers.helpers.notAllowed(req, res);
}
next();
};
middleware.checkAccountPermissions = function(req, res, next) {
// This middleware ensures that only the requested user and admins can pass
async.waterfall([
function (next) {
middleware.authenticate(req, res, next);
},
function (next) {
user.getUidByUserslug(req.params.userslug, next);
},
function (uid, next) {
if (parseInt(uid, 10) === req.uid) {
return next(null, true);
}
user.isAdminOrGlobalMod(req.uid, next);
}
], function (err, allowed) {
if (err || allowed) {
return next(err);
}
controllers.helpers.notAllowed(req, res);
});
};
middleware.redirectToAccountIfLoggedIn = function(req, res, next) {
if (req.session.forceLogin) {
return next();
}
if (!req.user) {
return next();
}
user.getUserField(req.user.uid, 'userslug', function (err, userslug) {
if (err) {
return next(err);
}
controllers.helpers.redirect(res, '/user/' + userslug);
});
};
middleware.redirectUidToUserslug = function(req, res, next) {
var uid = parseInt(req.params.uid, 10);
if (!uid) {
return next();
}
user.getUserField(uid, 'userslug', function(err, userslug) {
if (err || !userslug) {
return next(err);
}
var path = req.path.replace(/^\/api/, '')
.replace('uid', 'user')
.replace(uid, function() { return userslug; });
controllers.helpers.redirect(res, path);
});
};
middleware.isAdmin = function(req, res, next) {
if (!req.uid) {
return controllers.helpers.notAllowed(req, res);
}
user.isAdministrator(req.uid, function (err, isAdmin) {
if (err) {
return next(err);
}
if (isAdmin) {
user.hasPassword(req.uid, function(err, hasPassword) {
if (err) {
return next(err);
}
if (!hasPassword) {
return next();
}
var loginTime = req.session.meta ? req.session.meta.datetime : 0;
if (loginTime && parseInt(loginTime, 10) > Date.now() - 3600000) {
var timeLeft = parseInt(loginTime, 10) - (Date.now() - 3600000);
if (timeLeft < 300000) {
req.session.meta.datetime += 300000;
}
return next();
}
req.session.returnTo = req.path.replace(/^\/api/, '');
req.session.forceLogin = 1;
if (res.locals.isAPI) {
res.status(401).json({});
} else {
res.redirect(nconf.get('relative_path') + '/login');
}
});
return;
}
if (res.locals.isAPI) {
return controllers.helpers.notAllowed(req, res);
}
middleware.buildHeader(req, res, function() {
controllers.helpers.notAllowed(req, res);
});
});
};
middleware.requireUser = function(req, res, next) {
if (req.user) {
return next();
}
res.status(403).render('403', {title: '[[global:403.title]]'});
};
middleware.registrationComplete = function(req, res, next) {
// If the user's session contains registration data, redirect the user to complete registration
if (!req.session.hasOwnProperty('registration')) {
return next();
} else {
if (!req.path.endsWith('/register/complete')) {
controllers.helpers.redirect(res, '/register/complete');
} else {
return next();
}
}
};
};

@ -10,12 +10,10 @@ var nconf = require('nconf');
var db = require('./database');
var emitter = require('./emitter');
var translator = require('../public/src/modules/translator');
var utils = require('../public/src/utils');
var hotswap = require('./hotswap');
var file = require('./file');
var controllers = require('./controllers');
var app;
var middleware;
@ -149,11 +147,13 @@ var middleware;
Plugins.reloadRoutes = function(callback) {
callback = callback || function() {};
var router = express.Router();
router.hotswapId = 'plugins';
router.render = function() {
app.render.apply(app, arguments);
};
var controllers = require('./controllers');
Plugins.fireHook('static:app.load', {app: app, router: router, middleware: middleware, controllers: controllers}, function(err) {
if (err) {
return winston.error('[plugins] Encountered error while executing post-router plugins hooks: ' + err.message);

@ -1,25 +1,35 @@
'use strict';
var path = require('path'),
fs = require('fs'),
nconf = require('nconf'),
express = require('express'),
app = express(),
server,
winston = require('winston'),
async = require('async'),
emailer = require('./emailer'),
meta = require('./meta'),
languages = require('./languages'),
logger = require('./logger'),
plugins = require('./plugins'),
middleware = require('./middleware'),
routes = require('./routes'),
emitter = require('./emitter'),
helpers = require('../public/src/modules/helpers');
var fs = require('fs');
var path = require('path');
var nconf = require('nconf');
var express = require('express');
var app = express();
var server;
var winston = require('winston');
var async = require('async');
var flash = require('connect-flash');
var compression = require('compression');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var useragent = require('express-useragent');
var db = require('./database');
var file = require('./file');
var emailer = require('./emailer');
var meta = require('./meta');
var languages = require('./languages');
var logger = require('./logger');
var plugins = require('./plugins');
var middleware = require('./middleware');
var routes = require('./routes');
var auth = require('./routes/authentication');
var emitter = require('./emitter');
var templates = require('templates.js');
var helpers = require('../public/src/modules/helpers');
if (nconf.get('ssl')) {
server = require('https').createServer({
@ -46,7 +56,7 @@ server.on('error', function(err) {
module.exports.listen = function() {
emailer.registerApp(app);
app.locals.middleware = middleware = middleware(app);
setupExpressApp(app);
helpers.register();
@ -71,6 +81,69 @@ module.exports.listen = function() {
});
};
function setupExpressApp(app) {
var relativePath = nconf.get('relative_path');
app.engine('tpl', templates.__express);
app.set('view engine', 'tpl');
app.set('views', nconf.get('views_dir'));
app.set('json spaces', process.env.NODE_ENV === 'development' ? 4 : 0);
app.use(flash());
app.enable('view cache');
app.use(compression());
setupFavicon(app);
app.use(relativePath + '/apple-touch-icon', middleware.routeTouchIcon);
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.use(cookieParser());
app.use(useragent.express());
var cookie = {
maxAge: 1000 * 60 * 60 * 24 * (parseInt(meta.config.loginDays, 10) || 14)
};
if (meta.config.cookieDomain) {
cookie.domain = meta.config.cookieDomain;
}
if (nconf.get('secure')) {
cookie.secure = true;
}
if (relativePath !== '') {
cookie.path = relativePath;
}
app.use(session({
store: db.sessionStore,
secret: nconf.get('secret'),
key: 'express.sid',
cookie: cookie,
resave: true,
saveUninitialized: true
}));
app.use(middleware.addHeaders);
app.use(middleware.processRender);
auth.initialize(app, middleware);
var toobusy = require('toobusy-js');
toobusy.maxLag(parseInt(meta.config.eventLoopLagThreshold, 10) || 100);
toobusy.interval(parseInt(meta.config.eventLoopInterval, 10) || 500);
}
function setupFavicon(app) {
var faviconPath = path.join(__dirname, '../../', 'public', meta.config['brand:favicon'] ? meta.config['brand:favicon'] : 'favicon.ico');
if (file.existsSync(faviconPath)) {
app.use(nconf.get('relative_path'), favicon(faviconPath));
}
}
function initializeNodeBB(callback) {
var skipJS, skipLess, fromFile = nconf.get('from-file') || '';

Loading…
Cancel
Save