mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-28 09:36:16 +01:00
feat: #7743, webserver
This commit is contained in:
@@ -761,3 +761,5 @@ Flags.notify = function (flagObj, uid, callback) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
require('./promisify')(Flags);
|
||||||
|
|||||||
@@ -125,9 +125,9 @@ Plugins.reload = async function () {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Plugins.reloadRoutes = async function (router) {
|
Plugins.reloadRoutes = async function (params) {
|
||||||
var controllers = require('../controllers');
|
var controllers = require('../controllers');
|
||||||
await Plugins.fireHook('static:app.load', { app: app, router: router, middleware: middleware, controllers: controllers });
|
await Plugins.fireHook('static:app.load', { app: app, router: params.router, middleware: middleware, controllers: controllers });
|
||||||
winston.verbose('[plugins] All plugins reloaded and rerouted');
|
winston.verbose('[plugins] All plugins reloaded and rerouted');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -46,98 +46,89 @@ Auth.getLoginStrategies = function () {
|
|||||||
return loginStrategies;
|
return loginStrategies;
|
||||||
};
|
};
|
||||||
|
|
||||||
Auth.reloadRoutes = function (router, callback) {
|
Auth.reloadRoutes = async function (params) {
|
||||||
loginStrategies.length = 0;
|
loginStrategies.length = 0;
|
||||||
|
const router = params.router;
|
||||||
if (plugins.hasListeners('action:auth.overrideLogin')) {
|
if (plugins.hasListeners('action:auth.overrideLogin')) {
|
||||||
winston.warn('[authentication] Login override detected, skipping local login strategy.');
|
winston.warn('[authentication] Login override detected, skipping local login strategy.');
|
||||||
plugins.fireHook('action:auth.overrideLogin');
|
plugins.fireHook('action:auth.overrideLogin');
|
||||||
} else {
|
} else {
|
||||||
passport.use(new passportLocal({ passReqToCallback: true }, controllers.authentication.localLogin));
|
passport.use(new passportLocal({ passReqToCallback: true }, controllers.authentication.localLogin));
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
loginStrategies = await plugins.fireHook('filter:auth.init', loginStrategies);
|
||||||
|
} catch (err) {
|
||||||
|
winston.error('[authentication] ' + err.stack);
|
||||||
|
}
|
||||||
|
|
||||||
async.waterfall([
|
loginStrategies = loginStrategies || [];
|
||||||
function (next) {
|
loginStrategies.forEach(function (strategy) {
|
||||||
plugins.fireHook('filter:auth.init', loginStrategies, function (err) {
|
if (strategy.url) {
|
||||||
if (err) {
|
router.get(strategy.url, Auth.middleware.applyCSRF, function (req, res, next) {
|
||||||
winston.error('[authentication] ' + err.stack);
|
req.session.ssoState = req.csrfToken();
|
||||||
}
|
passport.authenticate(strategy.name, {
|
||||||
next(null, loginStrategies);
|
scope: strategy.scope,
|
||||||
|
prompt: strategy.prompt || undefined,
|
||||||
|
state: req.session.ssoState,
|
||||||
|
})(req, res, next);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
function (loginStrategies, next) {
|
|
||||||
loginStrategies = loginStrategies || [];
|
|
||||||
loginStrategies.forEach(function (strategy) {
|
|
||||||
if (strategy.url) {
|
|
||||||
router.get(strategy.url, Auth.middleware.applyCSRF, function (req, res, next) {
|
|
||||||
req.session.ssoState = req.csrfToken();
|
|
||||||
passport.authenticate(strategy.name, {
|
|
||||||
scope: strategy.scope,
|
|
||||||
prompt: strategy.prompt || undefined,
|
|
||||||
state: req.session.ssoState,
|
|
||||||
})(req, res, next);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
router[strategy.callbackMethod || 'get'](strategy.callbackURL, function (req, res, next) {
|
router[strategy.callbackMethod || 'get'](strategy.callbackURL, function (req, res, next) {
|
||||||
// Ensure the passed-back state value is identical to the saved ssoState (unless explicitly skipped)
|
// Ensure the passed-back state value is identical to the saved ssoState (unless explicitly skipped)
|
||||||
if (strategy.checkState === false) {
|
if (strategy.checkState === false) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
next(req.query.state !== req.session.ssoState ? new Error('[[error:csrf-invalid]]') : null);
|
|
||||||
}, function (req, res, next) {
|
|
||||||
// Trigger registration interstitial checks
|
|
||||||
req.session.registration = req.session.registration || {};
|
|
||||||
// save returnTo for later usage in /register/complete
|
|
||||||
// passport seems to remove `req.session.returnTo` after it redirects
|
|
||||||
req.session.registration.returnTo = req.session.returnTo;
|
|
||||||
next();
|
|
||||||
}, function (req, res, next) {
|
|
||||||
passport.authenticate(strategy.name, function (err, user) {
|
|
||||||
if (err) {
|
|
||||||
delete req.session.registration;
|
|
||||||
return next(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
delete req.session.registration;
|
|
||||||
return helpers.redirect(res, strategy.failureUrl !== undefined ? strategy.failureUrl : '/login');
|
|
||||||
}
|
|
||||||
|
|
||||||
res.locals.user = user;
|
|
||||||
res.locals.strategy = strategy;
|
|
||||||
next();
|
|
||||||
})(req, res, next);
|
|
||||||
},
|
|
||||||
Auth.middleware.validateAuth,
|
|
||||||
(req, res, next) => {
|
|
||||||
async.waterfall([
|
|
||||||
async.apply(req.login.bind(req), res.locals.user),
|
|
||||||
async.apply(controllers.authentication.onSuccessfulLogin, req, req.uid),
|
|
||||||
], function (err) {
|
|
||||||
if (err) {
|
|
||||||
return next(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
helpers.redirect(res, strategy.successUrl !== undefined ? strategy.successUrl : '/');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
var multipart = require('connect-multiparty');
|
|
||||||
var multipartMiddleware = multipart();
|
|
||||||
var middlewares = [multipartMiddleware, Auth.middleware.applyCSRF, Auth.middleware.applyBlacklist];
|
|
||||||
|
|
||||||
router.post('/register', middlewares, controllers.authentication.register);
|
|
||||||
router.post('/register/complete', middlewares, controllers.authentication.registerComplete);
|
|
||||||
router.post('/register/abort', controllers.authentication.registerAbort);
|
|
||||||
router.post('/login', Auth.middleware.applyCSRF, Auth.middleware.applyBlacklist, controllers.authentication.login);
|
|
||||||
router.post('/logout', Auth.middleware.applyCSRF, controllers.authentication.logout);
|
|
||||||
|
|
||||||
|
next(req.query.state !== req.session.ssoState ? new Error('[[error:csrf-invalid]]') : null);
|
||||||
|
}, function (req, res, next) {
|
||||||
|
// Trigger registration interstitial checks
|
||||||
|
req.session.registration = req.session.registration || {};
|
||||||
|
// save returnTo for later usage in /register/complete
|
||||||
|
// passport seems to remove `req.session.returnTo` after it redirects
|
||||||
|
req.session.registration.returnTo = req.session.returnTo;
|
||||||
next();
|
next();
|
||||||
|
}, function (req, res, next) {
|
||||||
|
passport.authenticate(strategy.name, function (err, user) {
|
||||||
|
if (err) {
|
||||||
|
delete req.session.registration;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
delete req.session.registration;
|
||||||
|
return helpers.redirect(res, strategy.failureUrl !== undefined ? strategy.failureUrl : '/login');
|
||||||
|
}
|
||||||
|
|
||||||
|
res.locals.user = user;
|
||||||
|
res.locals.strategy = strategy;
|
||||||
|
next();
|
||||||
|
})(req, res, next);
|
||||||
},
|
},
|
||||||
], callback);
|
Auth.middleware.validateAuth,
|
||||||
|
(req, res, next) => {
|
||||||
|
async.waterfall([
|
||||||
|
async.apply(req.login.bind(req), res.locals.user),
|
||||||
|
async.apply(controllers.authentication.onSuccessfulLogin, req, req.uid),
|
||||||
|
], function (err) {
|
||||||
|
if (err) {
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
helpers.redirect(res, strategy.successUrl !== undefined ? strategy.successUrl : '/');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var multipart = require('connect-multiparty');
|
||||||
|
var multipartMiddleware = multipart();
|
||||||
|
var middlewares = [multipartMiddleware, Auth.middleware.applyCSRF, Auth.middleware.applyBlacklist];
|
||||||
|
|
||||||
|
router.post('/register', middlewares, controllers.authentication.register);
|
||||||
|
router.post('/register/complete', middlewares, controllers.authentication.registerComplete);
|
||||||
|
router.post('/register/abort', controllers.authentication.registerAbort);
|
||||||
|
router.post('/login', Auth.middleware.applyCSRF, Auth.middleware.applyBlacklist, controllers.authentication.login);
|
||||||
|
router.post('/logout', Auth.middleware.applyCSRF, controllers.authentication.logout);
|
||||||
};
|
};
|
||||||
|
|
||||||
passport.serializeUser(function (user, done) {
|
passport.serializeUser(function (user, done) {
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
var nconf = require('nconf');
|
var nconf = require('nconf');
|
||||||
var winston = require('winston');
|
var winston = require('winston');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var async = require('async');
|
|
||||||
var express = require('express');
|
var express = require('express');
|
||||||
|
|
||||||
var meta = require('../meta');
|
var meta = require('../meta');
|
||||||
@@ -90,7 +89,7 @@ function groupRoutes(app, middleware, controllers) {
|
|||||||
setupPageRoute(app, '/groups/:slug/members', middleware, middlewares, controllers.groups.members);
|
setupPageRoute(app, '/groups/:slug/members', middleware, middlewares, controllers.groups.members);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = function (app, middleware, callback) {
|
module.exports = async function (app, middleware) {
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
router.render = function () {
|
router.render = function () {
|
||||||
app.render.apply(app, arguments);
|
app.render.apply(app, arguments);
|
||||||
@@ -109,21 +108,15 @@ module.exports = function (app, middleware, callback) {
|
|||||||
// homepage handled by `action:homepage.get:[route]`
|
// homepage handled by `action:homepage.get:[route]`
|
||||||
setupPageRoute(router, '/', middleware, [], controllers.home.pluginHook);
|
setupPageRoute(router, '/', middleware, [], controllers.home.pluginHook);
|
||||||
|
|
||||||
async.series([
|
await plugins.reloadRoutes({ router: router });
|
||||||
async.apply(plugins.reloadRoutes, router),
|
await authRoutes.reloadRoutes({ router: router });
|
||||||
async.apply(authRoutes.reloadRoutes, router),
|
addCoreRoutes(app, router, middleware);
|
||||||
async.apply(addCoreRoutes, app, router, middleware),
|
await user.addInterstitials();
|
||||||
async.apply(user.addInterstitials),
|
|
||||||
function (next) {
|
winston.info('Routes added');
|
||||||
winston.info('Routes added');
|
|
||||||
next();
|
|
||||||
},
|
|
||||||
], function (err) {
|
|
||||||
callback(err);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function addCoreRoutes(app, router, middleware, callback) {
|
function addCoreRoutes(app, router, middleware) {
|
||||||
adminRoutes(router, middleware, controllers);
|
adminRoutes(router, middleware, controllers);
|
||||||
metaRoutes(router, middleware, controllers);
|
metaRoutes(router, middleware, controllers);
|
||||||
apiRoutes(router, middleware, controllers);
|
apiRoutes(router, middleware, controllers);
|
||||||
@@ -190,5 +183,4 @@ function addCoreRoutes(app, router, middleware, callback) {
|
|||||||
app.use(controllers['404'].handle404);
|
app.use(controllers['404'].handle404);
|
||||||
app.use(controllers.errors.handleURIErrors);
|
app.use(controllers.errors.handleURIErrors);
|
||||||
app.use(controllers.errors.handleErrors);
|
app.use(controllers.errors.handleErrors);
|
||||||
setImmediate(callback);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
|
const util = require('util');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var os = require('os');
|
var os = require('os');
|
||||||
var nconf = require('nconf');
|
var nconf = require('nconf');
|
||||||
@@ -65,7 +66,7 @@ server.on('connection', function (conn) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports.destroy = function (callback) {
|
exports.destroy = function (callback) {
|
||||||
server.close(callback);
|
server.close(callback);
|
||||||
for (var key in connections) {
|
for (var key in connections) {
|
||||||
if (connections.hasOwnProperty(key)) {
|
if (connections.hasOwnProperty(key)) {
|
||||||
@@ -74,76 +75,45 @@ module.exports.destroy = function (callback) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.listen = function (callback) {
|
exports.listen = async function () {
|
||||||
callback = callback || function () { };
|
|
||||||
emailer.registerApp(app);
|
emailer.registerApp(app);
|
||||||
|
setupExpressApp(app);
|
||||||
|
helpers.register();
|
||||||
|
logger.init(app);
|
||||||
|
await initializeNodeBB();
|
||||||
|
winston.info('NodeBB Ready');
|
||||||
|
|
||||||
async.waterfall([
|
require('./socket.io').server.emit('event:nodebb.ready', {
|
||||||
function (next) {
|
'cache-buster': meta.config['cache-buster'],
|
||||||
setupExpressApp(app, next);
|
hostname: os.hostname(),
|
||||||
},
|
});
|
||||||
function (next) {
|
|
||||||
helpers.register();
|
|
||||||
|
|
||||||
logger.init(app);
|
plugins.fireHook('action:nodebb.ready');
|
||||||
|
|
||||||
initializeNodeBB(next);
|
await util.promisify(listen)();
|
||||||
},
|
|
||||||
function (next) {
|
|
||||||
winston.info('NodeBB Ready');
|
|
||||||
|
|
||||||
require('./socket.io').server.emit('event:nodebb.ready', {
|
|
||||||
'cache-buster': meta.config['cache-buster'],
|
|
||||||
hostname: os.hostname(),
|
|
||||||
});
|
|
||||||
|
|
||||||
plugins.fireHook('action:nodebb.ready');
|
|
||||||
|
|
||||||
listen(next);
|
|
||||||
},
|
|
||||||
], callback);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function initializeNodeBB(callback) {
|
async function initializeNodeBB() {
|
||||||
var middleware = require('./middleware');
|
const middleware = require('./middleware');
|
||||||
|
await meta.themes.setupPaths();
|
||||||
async.waterfall([
|
await plugins.init(app, middleware);
|
||||||
function (next) {
|
await plugins.fireHook('static:assets.prepare', {});
|
||||||
meta.themes.setupPaths(next);
|
await plugins.fireHook('static:app.preload', {
|
||||||
},
|
app: app,
|
||||||
function (next) {
|
middleware: middleware,
|
||||||
plugins.init(app, middleware, next);
|
|
||||||
},
|
|
||||||
async.apply(plugins.fireHook, 'static:assets.prepare', {}),
|
|
||||||
function (next) {
|
|
||||||
plugins.fireHook('static:app.preload', {
|
|
||||||
app: app,
|
|
||||||
middleware: middleware,
|
|
||||||
}, next);
|
|
||||||
},
|
|
||||||
function (next) {
|
|
||||||
routes(app, middleware, next);
|
|
||||||
},
|
|
||||||
function (next) {
|
|
||||||
meta.sounds.addUploads(next);
|
|
||||||
},
|
|
||||||
function (next) {
|
|
||||||
meta.blacklist.load(next);
|
|
||||||
},
|
|
||||||
function (next) {
|
|
||||||
flags.init(next);
|
|
||||||
},
|
|
||||||
], function (err) {
|
|
||||||
callback(err);
|
|
||||||
});
|
});
|
||||||
|
await routes(app, middleware);
|
||||||
|
await meta.sounds.addUploads();
|
||||||
|
await meta.blacklist.load();
|
||||||
|
await flags.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupExpressApp(app, callback) {
|
function setupExpressApp(app) {
|
||||||
var middleware = require('./middleware');
|
const middleware = require('./middleware');
|
||||||
var pingController = require('./controllers/ping');
|
const pingController = require('./controllers/ping');
|
||||||
|
|
||||||
var relativePath = nconf.get('relative_path');
|
const relativePath = nconf.get('relative_path');
|
||||||
var viewsDir = nconf.get('views_dir');
|
const viewsDir = nconf.get('views_dir');
|
||||||
|
|
||||||
app.engine('tpl', function (filepath, data, next) {
|
app.engine('tpl', function (filepath, data, next) {
|
||||||
filepath = filepath.replace(/\.tpl$/, '.js');
|
filepath = filepath.replace(/\.tpl$/, '.js');
|
||||||
@@ -210,8 +180,6 @@ function setupExpressApp(app, callback) {
|
|||||||
var toobusy = require('toobusy-js');
|
var toobusy = require('toobusy-js');
|
||||||
toobusy.maxLag(meta.config.eventLoopLagThreshold);
|
toobusy.maxLag(meta.config.eventLoopLagThreshold);
|
||||||
toobusy.interval(meta.config.eventLoopInterval);
|
toobusy.interval(meta.config.eventLoopInterval);
|
||||||
|
|
||||||
callback();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupFavicon(app) {
|
function setupFavicon(app) {
|
||||||
@@ -308,7 +276,7 @@ function listen(callback) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.testSocket = function (socketPath, callback) {
|
exports.testSocket = function (socketPath, callback) {
|
||||||
if (typeof socketPath !== 'string') {
|
if (typeof socketPath !== 'string') {
|
||||||
return callback(new Error('invalid socket path : ' + socketPath));
|
return callback(new Error('invalid socket path : ' + socketPath));
|
||||||
}
|
}
|
||||||
@@ -337,3 +305,5 @@ module.exports.testSocket = function (socketPath, callback) {
|
|||||||
async.apply(fs.unlink, socketPath), // The socket was stale, kick it out of the way
|
async.apply(fs.unlink, socketPath), // The socket was stale, kick it out of the way
|
||||||
], callback);
|
], callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
require('./promisify')(exports);
|
||||||
|
|||||||
Reference in New Issue
Block a user