diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index 53f979224a..993e45eb81 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -63,6 +63,10 @@ $(document).ready(function() { url = ajaxify.start(url, quiet); + if (!window.location.pathname.match(/\/(403|404)$/g)) { + app.previousUrl = window.location.href; + } + $('body').removeClass(ajaxify.data.bodyClass); $('#footer, #content').removeClass('hide').addClass('ajaxifying'); @@ -85,9 +89,10 @@ $(document).ready(function() { ajaxify.handleRedirects = function(url) { url = ajaxify.removeRelativePath(url.replace(/\/$/, '')).toLowerCase(); - var isAdminRoute = url.startsWith('admin') && window.location.pathname.indexOf(RELATIVE_PATH + '/admin') !== 0; + var isClientToAdmin = url.startsWith('admin') && window.location.pathname.indexOf(RELATIVE_PATH + '/admin') !== 0; + var isAdminToClient = !url.startsWith('admin') && window.location.pathname.indexOf(RELATIVE_PATH + '/admin') === 0; var uploadsOrApi = url.startsWith('uploads') || url.startsWith('api'); - if (isAdminRoute || uploadsOrApi) { + if (isClientToAdmin || isAdminToClient || uploadsOrApi) { window.open(RELATIVE_PATH + '/' + url, '_top'); return true; } @@ -100,10 +105,6 @@ $(document).ready(function() { $(window).trigger('action:ajaxify.start', {url: url}); - if (!window.location.pathname.match(/\/(403|404)$/g)) { - app.previousUrl = window.location.href; - } - ajaxify.currentPage = url.split(/[?#]/)[0]; if (window.history && window.history.pushState) { window.history[!quiet ? 'pushState' : 'replaceState']({ @@ -136,7 +137,8 @@ $(document).ready(function() { } else if (status === 401) { app.alertError('[[global:please_log_in]]'); app.previousUrl = url; - return ajaxify.go('login'); + window.location.href = config.relative_path + '/login'; + return; } else if (status === 302 || status === 308) { if (data.responseJSON.external) { window.location.href = data.responseJSON.external; diff --git a/public/src/client/login.js b/public/src/client/login.js index ecbd607f05..85aeb68be5 100644 --- a/public/src/client/login.js +++ b/public/src/client/login.js @@ -45,7 +45,12 @@ define('forum/login', ['csrf', 'translator'], function(csrf, translator) { return false; }); - $('#content #username').focus(); + if ($('#content #username').attr('readonly')) { + $('#content #password').focus(); + } else { + $('#content #username').focus(); + } + // Add "returnTo" data if present if (app.previousUrl) { diff --git a/src/controllers/authentication.js b/src/controllers/authentication.js index 560965f8ec..0912d99ac9 100644 --- a/src/controllers/authentication.js +++ b/src/controllers/authentication.js @@ -208,6 +208,8 @@ authenticationController.onSuccessfulLogin = function(req, uid, callback) { var uuid = utils.generateUUID(); req.session.meta = {}; + delete req.session.forceLogin; + // Associate IP used during login with user account user.logIP(uid, req.ip); req.session.meta.ip = req.ip; diff --git a/src/controllers/index.js b/src/controllers/index.js index 282d6c1f0a..0a3bf6f67f 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -95,15 +95,17 @@ Controllers.reset = function(req, res, next) { }; Controllers.login = function(req, res, next) { - var data = {}, - loginStrategies = require('../routes/authentication').getLoginStrategies(), - registrationType = meta.config.registrationType || 'normal'; + var data = {}; + var loginStrategies = require('../routes/authentication').getLoginStrategies(); + var registrationType = meta.config.registrationType || 'normal'; + + var allowLoginWith = (meta.config.allowLoginWith || 'username-email'); data.alternate_logins = loginStrategies.length > 0; data.authentication = loginStrategies; data.allowLocalLogin = parseInt(meta.config.allowLocalLogin, 10) === 1 || parseInt(req.query.local, 10) === 1; data.allowRegistration = registrationType === 'normal' || registrationType === 'admin-approval'; - data.allowLoginWith = '[[login:' + (meta.config.allowLoginWith || 'username-email') + ']]'; + data.allowLoginWith = '[[login:' + allowLoginWith + ']]'; data.breadcrumbs = helpers.buildBreadcrumbs([{text: '[[global:login]]'}]); data.error = req.flash('error')[0]; data.title = '[[pages:login]]'; @@ -113,8 +115,18 @@ Controllers.login = function(req, res, next) { external: data.authentication[0].url }); } + if (req.uid) { + user.getUserFields(req.uid, ['username', 'email'], function(err, user) { + if (err) { + return next(err); + } + data.username = allowLoginWith === 'email' ? user.email : user.username; + res.render('login', data); + }); + } else { + res.render('login', data); + } - res.render('login', data); }; Controllers.register = function(req, res, next) { diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js index d09270c3c9..184ea28a78 100644 --- a/src/middleware/middleware.js +++ b/src/middleware/middleware.js @@ -87,7 +87,9 @@ middleware.addHeaders = function (req, res, next) { headers = _.pick(headers, Boolean); // Remove falsy headers for(var key in headers) { - res.setHeader(key, headers[key]); + if (headers.hasOwnProperty(key)) { + res.setHeader(key, headers[key]); + } } next(); @@ -103,6 +105,10 @@ middleware.pluginHooks = function(req, res, next) { }; middleware.redirectToAccountIfLoggedIn = function(req, res, next) { + if (req.session.forceLogin) { + return next(); + } + if (!req.user) { return next(); } @@ -165,10 +171,26 @@ middleware.isAdmin = function(req, res, next) { } user.isAdministrator(req.uid, function (err, isAdmin) { - if (err || isAdmin) { + if (err) { return next(err); } + if (isAdmin) { + var loginTime = req.session.meta ? req.session.meta.datetime : 0; + if (loginTime && parseInt(loginTime, 10) > Date.now() - 3600000) { + return next(); + } + + req.session.returnTo = nconf.get('relative_path') + req.path.replace(/^\/api/, ''); + req.session.forceLogin = 1; + if (res.locals.isAPI) { + res.status(401).json({}); + } else { + res.redirect('/login'); + } + return; + } + if (res.locals.isAPI) { return controllers.helpers.notAllowed(req, res); }