diff --git a/public/language/en_GB/error.json b/public/language/en_GB/error.json index b6ddd1a2bb..a5e7cf9cbe 100644 --- a/public/language/en_GB/error.json +++ b/public/language/en_GB/error.json @@ -36,6 +36,7 @@ "password-too-long": "Password too long", "user-banned": "User banned", + "user-banned-reason": "User banned (Reason: %1)", "user-too-new": "Sorry, you are required to wait %1 second(s) before making your first post", "blacklisted-ip": "Sorry, your IP address has been banned from this community. If you feel this is in error, please contact an administrator.", "ban-expiry-missing": "Please provide an end date for this ban", diff --git a/src/controllers/authentication.js b/src/controllers/authentication.js index 0f74827be2..e0dc2f5649 100644 --- a/src/controllers/authentication.js +++ b/src/controllers/authentication.js @@ -379,7 +379,14 @@ authenticationController.localLogin = function(req, username, password, next) { return next(new Error('[[error:invalid-user-data]]')); } if (result.banned) { - return next(new Error('[[error:user-banned]]')); + // Retrieve ban reason and show error + return user.getLatestBanInfo(uid, function(err, banInfo) { + if (banInfo.reason) { + next(new Error('[[error:user-banned-reason, ' + banInfo.reason + ']]')); + } else { + next(new Error('[[error:user-banned]]')); + } + }); } Password.compare(password, userData.password, next); diff --git a/src/user/info.js b/src/user/info.js index fdd401dcd8..bd4eded9f5 100644 --- a/src/user/info.js +++ b/src/user/info.js @@ -2,12 +2,44 @@ var async = require('async'); var _ = require('underscore'); +var validator = require('validator'); var db = require('../database'); var posts = require('../posts'); var topics = require('../topics'); module.exports = function(User) { + User.getLatestBanInfo = function(uid, callback) { + // Simply retrieves the last record of the user's ban, even if they've been unbanned since then. + var timestamp, expiry, reason; + + async.waterfall([ + async.apply(db.getSortedSetRevRangeWithScores, 'uid:' + uid + ':bans', 0, 0), + function(record, next) { + timestamp = record[0].score; + expiry = record[0].value; + + db.getSortedSetRangeByScore('banned:' + uid + ':reasons', 0, -1, timestamp, timestamp, next); + }, + function(_reason, next) { + reason = _reason && _reason.length ? _reason[0] : ''; + next(); + } + ], function(err) { + if (err) { + return callback(err); + } + + callback(null, { + uid: uid, + timestamp: timestamp, + expiry: parseInt(expiry, 10), + expiry_readable: new Date(parseInt(expiry, 10)).toString().replace(/:/g, '%3A'), + reason: validator.escape(String(reason)) + }); + }) + }; + User.getModerationHistory = function(uid, callback) { async.waterfall([ function(next) { @@ -76,7 +108,7 @@ module.exports = function(User) { banObj.timestamp = parseInt(banObj.score, 10); banObj.timestampReadable = new Date(banObj.score).toString(); banObj.timestampISO = new Date(banObj.score).toISOString(); - banObj.reason = reasons[banObj.score] || '[[user:info.banned-no-reason]]'; + banObj.reason = validator.escape(String(reasons[banObj.score])) || '[[user:info.banned-no-reason]]'; delete banObj.value; delete banObj.score;