organize middlewares
removed app.locals.middleware middlewares can be required anywhere, ie in controllersv1.18.x
parent
f5941cbf1c
commit
8f408faf46
@ -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;
|
||||
};
|
||||
};
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue