diff --git a/lib/controllers.js b/lib/controllers.js index 8e6710f..7b32da0 100644 --- a/lib/controllers.js +++ b/lib/controllers.js @@ -16,6 +16,13 @@ const user = require.main.require('./src/user'); const meta = require.main.require('./src/meta'); const helpers = require.main.require('./src/controllers/helpers'); +const guard = (path) => { + let url = new URL(path, nconf.get('url')); + url = url.hostname === nconf.get('url_parsed').hostname ? url : nconf.get('url'); + + return url.toString(); +}; + const Controllers = module.exports; @@ -70,7 +77,7 @@ Controllers.renderTotpChallenge = async (req, res, next) => { const single = parseInt(req.query.single, 10) === 1; if (req.session.tfa === true && !req.session.tfaForce) { - return res.redirect(nconf.get('relative_path') + (req.query.next || '/')); + return res.redirect(guard(nconf.get('relative_path') + (req.query.next || '/'))); } const error = req.flash('error'); @@ -97,7 +104,7 @@ Controllers.renderAuthnChallenge = async (req, res, next) => { const single = parseInt(req.query.single, 10) === 1; if (req.session.tfa === true && ((req.query.next && !req.query.next.startsWith('/admin')) || !req.session.tfaForce)) { - return res.redirect(nconf.get('relative_path') + (req.query.next || '/')); + return res.redirect(guard(nconf.get('relative_path') + (req.query.next || '/'))); } if (!await parent.hasAuthn(uid)) { @@ -137,7 +144,7 @@ Controllers.renderBackup = async (req, res, next) => { const single = parseInt(req.query.single, 10) === 1; if (req.session.tfa === true && ((req.query.next && !req.query.next.startsWith('/admin')) || !req.session.tfaForce)) { - return res.redirect(nconf.get('relative_path') + (req.query.next || '/')); + return res.redirect(guard(nconf.get('relative_path') + (req.query.next || '/'))); } const error = req.flash('error'); diff --git a/library.js b/library.js index f339b26..a698fd4 100644 --- a/library.js +++ b/library.js @@ -21,6 +21,12 @@ const controllerHelpers = require.main.require('./src/controllers/helpers'); const SocketPlugins = require.main.require('./src/socket.io/plugins'); const atob = base64str => Buffer.from(base64str, 'base64').toString('binary'); +const guard = (path) => { + let url = new URL(path, nconf.get('url')); + url = url.hostname === nconf.get('url_parsed').hostname ? url : nconf.get('url'); + + return url.toString(); +}; const plugin = { _f2l: undefined, @@ -57,7 +63,7 @@ plugin.init = async (params) => { delete req.session.tfaForce; req.session.meta.datetime = Date.now(); user.auth.addSession(req.uid, req.sessionID, req.session.meta.uuid); - res.redirect(nconf.get('relative_path') + (req.query.next || '/')); + res.redirect(guard(nconf.get('relative_path') + (req.query.next || '/'))); }); hostHelpers.setupPageRoute(router, '/login/2fa/authn', [hostMiddleware.ensureLoggedIn], controllers.renderAuthnChallenge); @@ -65,7 +71,7 @@ plugin.init = async (params) => { hostHelpers.setupPageRoute(router, '/login/2fa/backup', [hostMiddleware.ensureLoggedIn], controllers.renderBackup); router.post('/login/2fa/backup', hostMiddleware.ensureLoggedIn, controllers.processBackup, (req, res) => { req.session.tfa = true; - res.redirect(nconf.get('relative_path') + (req.query.next || '/')); + res.redirect(guard(nconf.get('relative_path') + (req.query.next || '/'))); }); router.put('/login/2fa/backup', hostMiddleware.requireUser, middlewares.requireSecondFactor, hostMiddleware.applyCSRF, controllers.generateBackupCodes); @@ -167,7 +173,7 @@ plugin.addRoutes = async ({ router, middleware, helpers }) => { req.session.meta.datetime = Date.now(); helpers.formatApiResponse(200, res, { - next: req.query.next || '/', + next: guard(req.query.next || '/'), }); }); diff --git a/static/lib/authn.js b/static/lib/authn.js index 4a0e600..0101e59 100644 --- a/static/lib/authn.js +++ b/static/lib/authn.js @@ -22,7 +22,7 @@ define('forum/login-authn', ['api', 'alerts', 'hooks'], function (api, alerts, h iconEl.classList.remove('fa-spin'); iconEl.classList.add('fa-check'); iconEl.classList.add('text-success'); - document.location = config.relative_path + next; + document.location = next; }).catch((err) => { alerts.error(err); ajaxify.refresh();