From d3ad21f81f0f93658b6f905367188ceb7c88a087 Mon Sep 17 00:00:00 2001 From: Ole R Date: Fri, 5 Feb 2016 10:12:07 +0100 Subject: [PATCH 01/34] Fix settings trim cleaning arrays --- src/settings.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/settings.js b/src/settings.js index 3d90dcfa84..6f3e1a0b36 100644 --- a/src/settings.js +++ b/src/settings.js @@ -20,6 +20,7 @@ function expandObjBy(obj1, obj2) { } function trim(obj1, obj2) { + if (obj1 instanceof Array) { return; } var key, val1; for (key in obj1) { if (obj1.hasOwnProperty(key)) { @@ -29,7 +30,7 @@ function trim(obj1, obj2) { } else if (typeof val1 === 'object') { trim(val1, obj2[key]); } - } + } } } From 7484389a4119ba80373c4ba3fbc8f489727e7bd4 Mon Sep 17 00:00:00 2001 From: Ole R Date: Wed, 10 Feb 2016 15:04:55 +0100 Subject: [PATCH 02/34] Update array-check to Array.isArray --- src/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/settings.js b/src/settings.js index 6f3e1a0b36..71e0ea1374 100644 --- a/src/settings.js +++ b/src/settings.js @@ -20,7 +20,7 @@ function expandObjBy(obj1, obj2) { } function trim(obj1, obj2) { - if (obj1 instanceof Array) { return; } + if (Array.isArray(obj1)) { return; } var key, val1; for (key in obj1) { if (obj1.hasOwnProperty(key)) { From f537dfee1622b2040f2ab88219fd82328c822b0b Mon Sep 17 00:00:00 2001 From: Ole R Date: Thu, 25 Feb 2016 11:01:46 +0100 Subject: [PATCH 03/34] Update array-check for settings trim and expand --- src/settings.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/settings.js b/src/settings.js index 71e0ea1374..6f6cad2854 100644 --- a/src/settings.js +++ b/src/settings.js @@ -3,16 +3,19 @@ var meta = require('./meta'); function expandObjBy(obj1, obj2) { - var key, val1, val2, changed = false; + var key, val1, val2, xorValIsArray, changed = false; for (key in obj2) { if (obj2.hasOwnProperty(key)) { val2 = obj2[key]; val1 = obj1[key]; - if (!obj1.hasOwnProperty(key) || typeof val2 !== typeof val1) { + xorValIsArray = Array.isArray(val1) ^ Array.isArray(val2); + if (xorValIsArray || !obj1.hasOwnProperty(key) || typeof val2 !== typeof val1) { obj1[key] = val2; changed = true; - } else if (typeof val2 === 'object' && expandObjBy(val1, val2)) { - changed = true; + } else if (typeof val2 === 'object' && !Array.isArray(val2)) { + if (expandObjBy(val1, val2)) { + changed = true; + } } } } @@ -20,14 +23,13 @@ function expandObjBy(obj1, obj2) { } function trim(obj1, obj2) { - if (Array.isArray(obj1)) { return; } var key, val1; for (key in obj1) { if (obj1.hasOwnProperty(key)) { val1 = obj1[key]; if (!obj2.hasOwnProperty(key)) { delete obj1[key]; - } else if (typeof val1 === 'object') { + } else if (typeof val1 === 'object' && !Array.isArray(val1)) { trim(val1, obj2[key]); } } From a402e29f2962cc6d7fc05da0162b07e7b7b75a44 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sun, 13 Mar 2016 11:05:59 +0200 Subject: [PATCH 04/34] up widget essentials --- package.json | 2 +- src/socket.io/admin/rooms.js | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index b035c2fbb2..d6599232e5 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "nodebb-theme-lavender": "3.0.9", "nodebb-theme-persona": "4.0.93", "nodebb-theme-vanilla": "5.0.54", - "nodebb-widget-essentials": "2.0.7", + "nodebb-widget-essentials": "2.0.8", "nodemailer": "2.0.0", "nodemailer-sendmail-transport": "1.0.0", "nodemailer-smtp-transport": "^2.4.1", diff --git a/src/socket.io/admin/rooms.js b/src/socket.io/admin/rooms.js index 6d8843b8ca..50ba4661de 100644 --- a/src/socket.io/admin/rooms.js +++ b/src/socket.io/admin/rooms.js @@ -29,15 +29,16 @@ pubsub.on('sync:stats:end', function(data) { stats[data.id] = data.stats; }); +pubsub.on('sync:stats:guests', function() { + var io = require('../index').server; + + var roomClients = io.sockets.adapter.rooms; + var guestCount = roomClients.online_guests ? roomClients.online_guests.length : 0; + pubsub.publish('sync:stats:guests:end', guestCount); +}); + SocketRooms.getTotalGuestCount = function(callback) { var count = 0; - pubsub.once('sync:stats:guests', function() { - var io = require('../index').server; - - var roomClients = io.sockets.adapter.rooms; - var guestCount = roomClients.online_guests ? roomClients.online_guests.length : 0; - pubsub.publish('sync:stats:guests:end', guestCount); - }); pubsub.on('sync:stats:guests:end', function(guestCount) { count += guestCount; From 147e36a7a5e586da1726ab9ae84124a8a4694c2c Mon Sep 17 00:00:00 2001 From: kingjan1999 Date: Mon, 14 Mar 2016 10:27:24 +0100 Subject: [PATCH 05/34] update fontawesome.tpl to FA 4.5 --- src/views/partials/fontawesome.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/partials/fontawesome.tpl b/src/views/partials/fontawesome.tpl index 6ede4e70d3..a179bfdd49 100644 --- a/src/views/partials/fontawesome.tpl +++ b/src/views/partials/fontawesome.tpl @@ -4,7 +4,7 @@
- +

For a full list of icons, please consult: From 0f917635c646cae317b71e53d5b22af68319f85d Mon Sep 17 00:00:00 2001 From: accalia Date: Mon, 14 Mar 2016 10:40:24 -0400 Subject: [PATCH 06/34] allow loadMore Calls to fetch page 0 --- src/socket.io/notifications.js | 3 ++- src/socket.io/topics/infinitescroll.js | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/socket.io/notifications.js b/src/socket.io/notifications.js index e2d7cf3084..121ede2a96 100644 --- a/src/socket.io/notifications.js +++ b/src/socket.io/notifications.js @@ -3,6 +3,7 @@ var async = require('async'); var user = require('../user'); var notifications = require('../notifications'); +var utils = require('../../public/src/utils'); var SocketNotifs = {}; @@ -15,7 +16,7 @@ SocketNotifs.get = function(socket, data, callback) { }; SocketNotifs.loadMore = function(socket, data, callback) { - if (!data || !parseInt(data.after, 10)) { + if (!data || !utils.isNumber(data.after) || parseInt(data.after, 10) < 0) { return callback(new Error('[[error:invalid-data]]')); } if (!socket.uid) { diff --git a/src/socket.io/topics/infinitescroll.js b/src/socket.io/topics/infinitescroll.js index 8cb975c15e..3ffe1c65c8 100644 --- a/src/socket.io/topics/infinitescroll.js +++ b/src/socket.io/topics/infinitescroll.js @@ -88,7 +88,7 @@ module.exports = function(SocketTopics) { }; SocketTopics.loadMoreUnreadTopics = function(socket, data, callback) { - if (!data || !data.after) { + if (!data || !utils.isNumber(data.after) || parseInt(data.after, 10) < 0) { return callback(new Error('[[error:invalid-data]]')); } @@ -99,7 +99,7 @@ module.exports = function(SocketTopics) { }; SocketTopics.loadMoreFromSet = function(socket, data, callback) { - if (!data || !data.after || !data.set) { + if (!data || !utils.isNumber(data.after) || parseInt(data.after, 10) < 0 || !data.set) { return callback(new Error('[[error:invalid-data]]')); } From a275aaeaf50a46590e157c183f51333f321b5b7e Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 14 Mar 2016 12:57:45 -0400 Subject: [PATCH 07/34] fixes #4361 --- public/src/admin/manage/categories.js | 55 ++++++++++++++++++--------- public/src/admin/manage/category.js | 6 +++ src/categories/update.js | 5 ++- 3 files changed, 46 insertions(+), 20 deletions(-) diff --git a/public/src/admin/manage/categories.js b/public/src/admin/manage/categories.js index a57fc06701..b4a5f19601 100644 --- a/public/src/admin/manage/categories.js +++ b/public/src/admin/manage/categories.js @@ -152,28 +152,45 @@ define('admin/manage/categories', ['vendor/jquery/serializeObject/jquery.ba-seri * @param parentId {number} parent category identifier */ function renderList(categories, container, parentId){ - templates.parse('admin/partials/categories/category-rows', { - cid: parentId, - categories: categories - }, function(html) { - container.append(html); + // Translate category names if needed + var count = 0; + categories.forEach(function(category, idx, parent) { + translator.translate(category.name, function(translated) { + if (category.name !== translated) { + category.name = translated; + } + ++count; - // Handle and children categories in this level have - for(var x=0,numCategories=categories.length;x Date: Mon, 14 Mar 2016 13:03:33 -0400 Subject: [PATCH 08/34] Updated topic and category controller to not redirect on incorrect slug if the call is made via API route. Cold load? Anything goes. --- src/controllers/category.js | 2 +- src/controllers/topics.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/category.js b/src/controllers/category.js index f4b939f60a..e3adde496f 100644 --- a/src/controllers/category.js +++ b/src/controllers/category.js @@ -51,7 +51,7 @@ categoryController.get = function(req, res, callback) { return helpers.notAllowed(req, res); } - if ((!req.params.slug || results.categoryData.slug !== cid + '/' + req.params.slug) && (results.categoryData.slug && results.categoryData.slug !== cid + '/')) { + if (!res.locals.isAPI && (!req.params.slug || results.categoryData.slug !== cid + '/' + req.params.slug) && (results.categoryData.slug && results.categoryData.slug !== cid + '/')) { return helpers.redirect(res, '/category/' + encodeURI(results.categoryData.slug)); } diff --git a/src/controllers/topics.js b/src/controllers/topics.js index 7a222dd09c..68a3b18415 100644 --- a/src/controllers/topics.js +++ b/src/controllers/topics.js @@ -54,7 +54,7 @@ topicsController.get = function(req, res, callback) { return helpers.notAllowed(req, res); } - if ((!req.params.slug || results.topic.slug !== tid + '/' + req.params.slug) && (results.topic.slug && results.topic.slug !== tid + '/')) { + if (!res.locals.isAPI && (!req.params.slug || results.topic.slug !== tid + '/' + req.params.slug) && (results.topic.slug && results.topic.slug !== tid + '/')) { var url = '/topic/' + encodeURI(results.topic.slug); if (req.params.post_index){ url += '/'+req.params.post_index; From 50b0bcca0ca6fdcf2f21b3e7831ef0cd4d7ea1f0 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 14 Mar 2016 15:30:27 -0400 Subject: [PATCH 09/34] closes #4291 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d6599232e5..7ee2d14430 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "mongodb": "~2.1.3", "morgan": "^1.3.2", "nconf": "~0.8.2", - "nodebb-plugin-composer-default": "3.0.7", + "nodebb-plugin-composer-default": "3.0.8", "nodebb-plugin-dbsearch": "1.0.0", "nodebb-plugin-emoji-extended": "1.0.3", "nodebb-plugin-markdown": "4.0.17", From 71c697037d7dc41b06cda6a63db97b0cd09acd84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 14 Mar 2016 22:10:02 +0200 Subject: [PATCH 10/34] return the ips of the account we are looking at --- src/controllers/accounts/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/accounts/settings.js b/src/controllers/accounts/settings.js index 7028972491..0b180be686 100644 --- a/src/controllers/accounts/settings.js +++ b/src/controllers/accounts/settings.js @@ -42,7 +42,7 @@ settingsController.get = function(req, res, callback) { getHomePageRoutes(next); }, ips: function (next) { - user.getIPs(req.uid, 4, next); + user.getIPs(userData.uid, 4, next); }, sessions: async.apply(user.auth.getSessions, userData.uid, req.sessionID) }, next); From 184a2c4540c95be87ba787aff2dab59a5f7522c0 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 14 Mar 2016 17:31:36 -0400 Subject: [PATCH 11/34] IP blacklist functionality -- re: #4367 Squashed commit of the following: commit 5c42fd732d091fa66cf5b45a2af5e1697cc1efcd Author: Julian Lam Date: Mon Mar 14 17:29:45 2016 -0400 allowing blacklist.test to be called synchronously commit 979faf2dba5e6f6e2ae1bd07341e63678438daf1 Author: Julian Lam Date: Mon Mar 14 17:01:14 2016 -0400 added plain ipv6 support and finished middleware logic commit d4b72fc1aadff34df3ed7dec52ca8d3c3728a078 Author: Julian Lam Date: Fri Mar 11 16:05:31 2016 -0500 WIP IP Banning logic middleware commit f08b2553890c5522b6a1eaf521fe4e94df40574a Author: Julian Lam Date: Fri Mar 11 15:26:27 2016 -0500 tweaks to ACP, rule validator commit 868abacaa494e6b8a88bd4ea429b1b066a9ecb2e Author: Julian Lam Date: Fri Mar 11 13:50:05 2016 -0500 IP Banning ACP page, styling, save&load functionality --- package.json | 1 + public/language/en_GB/error.json | 1 + public/less/admin/admin.less | 1 + public/less/admin/manage/blacklist.less | 5 + public/src/admin/manage/ip-blacklist.js | 41 +++++++ src/controllers/admin.js | 1 + src/controllers/admin/blacklist.js | 9 ++ src/meta.js | 1 + src/meta/blacklist.js | 106 ++++++++++++++++++ src/middleware/middleware.js | 7 ++ src/routes/admin.js | 2 +- src/routes/authentication.js | 4 +- src/routes/index.js | 11 +- src/socket.io/admin.js | 6 +- src/views/admin/manage/ip-blacklist.tpl | 31 +++++ .../admin/partials/blacklist-validate.tpl | 14 +++ src/views/admin/partials/menu.tpl | 2 + src/webserver.js | 3 +- 18 files changed, 238 insertions(+), 8 deletions(-) create mode 100644 public/less/admin/manage/blacklist.less create mode 100644 public/src/admin/manage/ip-blacklist.js create mode 100644 src/controllers/admin/blacklist.js create mode 100644 src/meta/blacklist.js create mode 100644 src/views/admin/manage/ip-blacklist.tpl create mode 100644 src/views/admin/partials/blacklist-validate.tpl diff --git a/package.json b/package.json index 7ee2d14430..37f7911604 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "express-session": "^1.8.2", "express-useragent": "0.2.4", "html-to-text": "2.0.0", + "ip": "1.1.2", "jimp": "0.2.21", "less": "^2.0.0", "logrotate-stream": "^0.2.3", diff --git a/public/language/en_GB/error.json b/public/language/en_GB/error.json index b60c8a2cde..e9a4cbea7d 100644 --- a/public/language/en_GB/error.json +++ b/public/language/en_GB/error.json @@ -34,6 +34,7 @@ "user-banned": "User banned", "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.", "no-category": "Category does not exist", "no-topic": "Topic does not exist", diff --git a/public/less/admin/admin.less b/public/less/admin/admin.less index 930e518412..182b0afccf 100644 --- a/public/less/admin/admin.less +++ b/public/less/admin/admin.less @@ -12,6 +12,7 @@ @import "./manage/tags"; @import "./manage/groups"; @import "./manage/users"; +@import "./manage/blacklist"; @import "./appearance/customise"; @import "./appearance/themes"; @import "./extend/plugins"; diff --git a/public/less/admin/manage/blacklist.less b/public/less/admin/manage/blacklist.less new file mode 100644 index 0000000000..4e0dcb7c27 --- /dev/null +++ b/public/less/admin/manage/blacklist.less @@ -0,0 +1,5 @@ +#blacklist-rules { + width: 100%; + height: 450px; + display: block; +} \ No newline at end of file diff --git a/public/src/admin/manage/ip-blacklist.js b/public/src/admin/manage/ip-blacklist.js new file mode 100644 index 0000000000..daba34ec3d --- /dev/null +++ b/public/src/admin/manage/ip-blacklist.js @@ -0,0 +1,41 @@ +'use strict'; +/* globals $, app, socket, templates */ + +define('admin/manage/ip-blacklist', ['settings'], function(Settings) { + + var Blacklist = {}; + + Blacklist.init = function() { + var blacklist = ace.edit("blacklist-rules"); + + blacklist.on('change', function(e) { + $('#blacklist-rules-holder').val(blacklist.getValue()); + }); + + Settings.load('blacklist', $('.blacklist-settings'), function(err, settings) { + blacklist.setValue(settings.rules); + }); + + $('[data-action="apply"]').on('click', function() { + Settings.save('blacklist', $('.blacklist-settings'), function() { + app.alert({ + type: 'success', + alert_id: 'blacklist-saved', + title: 'Blacklist Applied', + }); + }); + }); + + $('[data-action="test"]').on('click', function() { + socket.emit('admin.blacklist.validate', { + rules: blacklist.getValue() + }, function(err, data) { + templates.parse('admin/partials/blacklist-validate', data, function(html) { + bootbox.alert(html); + }); + }); + }); + }; + + return Blacklist; +}); \ No newline at end of file diff --git a/src/controllers/admin.js b/src/controllers/admin.js index 8b9b1cafc7..2bba60cae6 100644 --- a/src/controllers/admin.js +++ b/src/controllers/admin.js @@ -5,6 +5,7 @@ var adminController = { categories: require('./admin/categories'), tags: require('./admin/tags'), flags: require('./admin/flags'), + blacklist: require('./admin/blacklist'), groups: require('./admin/groups'), appearance: require('./admin/appearance'), extend: { diff --git a/src/controllers/admin/blacklist.js b/src/controllers/admin/blacklist.js new file mode 100644 index 0000000000..60c3940e44 --- /dev/null +++ b/src/controllers/admin/blacklist.js @@ -0,0 +1,9 @@ +"use strict"; + +var blacklistController = {}; + +blacklistController.get = function(req, res, next) { + res.render('admin/manage/ip-blacklist', {}); +}; + +module.exports = blacklistController; diff --git a/src/meta.js b/src/meta.js index 7a054b1836..716d90e9cb 100644 --- a/src/meta.js +++ b/src/meta.js @@ -26,6 +26,7 @@ var async = require('async'), require('./meta/tags')(Meta); require('./meta/dependencies')(Meta); Meta.templates = require('./meta/templates'); + Meta.blacklist = require('./meta/blacklist'); /* Assorted */ Meta.userOrGroupExists = function(slug, callback) { diff --git a/src/meta/blacklist.js b/src/meta/blacklist.js new file mode 100644 index 0000000000..2029b406f2 --- /dev/null +++ b/src/meta/blacklist.js @@ -0,0 +1,106 @@ +'use strict'; + +var ip = require('ip'), + winston = require('winston'), + async = require('async'); + +var meta = module.parent.exports; + +var Blacklist = { + _rules: [] + }; + +Blacklist.load = function(callback) { + async.waterfall([ + async.apply(meta.settings.getOne, 'blacklist', 'rules'), + async.apply(Blacklist.validate) + ], function(err, rules) { + if (err) { + return callback(err); + } + + winston.verbose('[meta/blacklist] Loading ' + rules.valid.length + ' blacklist rules'); + if (rules.invalid.length) { + winston.warn('[meta/blacklist] ' + rules.invalid.length + ' invalid blacklist rule(s) were ignored.'); + } + + Blacklist._rules = { + ipv4: rules.ipv4, + ipv6: rules.ipv6, + cidr: rules.cidr + }; + + callback(); + }); +}; + +Blacklist.test = function(clientIp, callback) { + if ( + Blacklist._rules.ipv4.indexOf(clientIp) === -1 // not explicitly specified in ipv4 list + && Blacklist._rules.ipv6.indexOf(clientIp) === -1 // not explicitly specified in ipv6 list + && !Blacklist._rules.cidr.some(function(subnet) { + return ip.cidrSubnet(subnet).contains(clientIp); + }) // not in a blacklisted cidr range + ) { + if (typeof callback === 'function') { + callback(); + } else { + return false; + } + } else { + var err = new Error('[[error:blacklisted-ip]]'); + err.code = 'blacklisted-ip'; + + if (typeof callback === 'function') { + callback(err); + } else { + return true; + } + } +}; + +Blacklist.validate = function(rules, callback) { + var rules = (rules || '').split('\n'), + ipv4 = [], + ipv6 = [], + cidr = [], + invalid = []; + + var isCidrSubnet = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$/; + + // Filter out blank lines and lines starting with the hash character (comments) + rules = rules.map(function(rule) { + rule = rule.trim(); + return rule.length && !rule.startsWith('#') ? rule : null; + }).filter(Boolean); + + // Filter out invalid rules + rules = rules.filter(function(rule) { + if (ip.isV4Format(rule)) { + ipv4.push(rule); + return true; + } else if (ip.isV6Format(rule)) { + ipv6.push(rule); + return true; + } else if (isCidrSubnet.test(rule)) { + cidr.push(rule); + return true; + } else { + invalid.push(rule); + return false; + } + + return true; + }); + + callback(null, { + numRules: rules.length + invalid.length, + ipv4: ipv4, + ipv6: ipv6, + cidr: cidr, + valid: rules, + invalid: invalid + }); +}; + +module.exports = Blacklist; \ No newline at end of file diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js index d5e1d93388..52adf21ab4 100644 --- a/src/middleware/middleware.js +++ b/src/middleware/middleware.js @@ -257,6 +257,13 @@ middleware.busyCheck = function(req, res, next) { } }; +middleware.applyBlacklist = function(req, res, next) { + meta.blacklist.test(req.ip, function(err) { + console.log('blacklist returned:', err); + next(err); + }); +}; + module.exports = function(webserver) { app = webserver; middleware.admin = require('./admin')(webserver); diff --git a/src/routes/admin.js b/src/routes/admin.js index f5d4d039a1..56c97ff1f2 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -54,8 +54,8 @@ function addRoutes(router, middleware, controllers) { router.get('/manage/categories/:category_id', middlewares, controllers.admin.categories.get); router.get('/manage/tags', middlewares, controllers.admin.tags.get); - router.get('/manage/flags', middlewares, controllers.admin.flags.get); + router.get('/manage/ip-blacklist', middlewares, controllers.admin.blacklist.get); router.get('/manage/users', middlewares, controllers.admin.users.sortByJoinDate); router.get('/manage/users/search', middlewares, controllers.admin.users.search); diff --git a/src/routes/authentication.js b/src/routes/authentication.js index 37439ba523..8e1824cad6 100644 --- a/src/routes/authentication.js +++ b/src/routes/authentication.js @@ -62,8 +62,8 @@ })); }); - router.post('/register', Auth.middleware.applyCSRF, controllers.authentication.register); - router.post('/login', Auth.middleware.applyCSRF, controllers.authentication.login); + router.post('/register', Auth.middleware.applyCSRF, Auth.middleware.applyBlacklist, controllers.authentication.register); + router.post('/login', Auth.middleware.applyCSRF, Auth.middleware.applyBlacklist, controllers.authentication.login); router.post('/logout', Auth.middleware.applyCSRF, controllers.authentication.logout); hotswap.replace('auth', router); diff --git a/src/routes/index.js b/src/routes/index.js index 7e84f29af1..e49256f933 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -187,9 +187,14 @@ function handle404(app, middleware) { function handleErrors(app, middleware) { app.use(function(err, req, res, next) { - if (err.code === 'EBADCSRFTOKEN') { - winston.error(req.path + '\n', err.message); - return res.sendStatus(403); + switch (err.code) { + case 'EBADCSRFTOKEN': + winston.error(req.path + '\n', err.message); + return res.sendStatus(403); + break; + case 'blacklisted-ip': + return res.status(403).type('text/plain').send(err.message); + break; } if (parseInt(err.status, 10) === 302 && err.path) { diff --git a/src/socket.io/admin.js b/src/socket.io/admin.js index 6dd22134ba..f3504a920d 100644 --- a/src/socket.io/admin.js +++ b/src/socket.io/admin.js @@ -33,7 +33,8 @@ var async = require('async'), settings: {}, email: {}, analytics: {}, - logs: {} + logs: {}, + blacklist: {} }; SocketAdmin.before = function(socket, method, data, next) { @@ -273,5 +274,8 @@ SocketAdmin.deleteAllEvents = function(socket, data, callback) { events.deleteAll(callback); }; +SocketAdmin.blacklist.validate = function(socket, data, callback) { + meta.blacklist.validate(data.rules, callback); +}; module.exports = SocketAdmin; diff --git a/src/views/admin/manage/ip-blacklist.tpl b/src/views/admin/manage/ip-blacklist.tpl new file mode 100644 index 0000000000..13e43a84d7 --- /dev/null +++ b/src/views/admin/manage/ip-blacklist.tpl @@ -0,0 +1,31 @@ +

+
+

+ Configure your IP blacklist here. +

+

+ Occasionally, a user account ban is not enough of a deterrant. Other times, restricting access to the forum to a specific IP or a range of IPs + is the best way to protect a forum. In these scenarios, you can add troublesome IP addresses or entire CIDR blocks to this blacklist, and + they will be prevented from logging in to or registering a new account. +

+ +
+
+
+
+ +
+
+
+
+
Active Rules
+
+ + +
+
+
+
+
+ +
\ No newline at end of file diff --git a/src/views/admin/partials/blacklist-validate.tpl b/src/views/admin/partials/blacklist-validate.tpl new file mode 100644 index 0000000000..4a642a23a3 --- /dev/null +++ b/src/views/admin/partials/blacklist-validate.tpl @@ -0,0 +1,14 @@ +

+ {valid.length} out of {numRules} rule(s) valid. +

+ + +

+ The following {invalid.length} rules are invalid: +

+
    + +
  • @value
  • + +
+ \ No newline at end of file diff --git a/src/views/admin/partials/menu.tpl b/src/views/admin/partials/menu.tpl index a0027c0621..8d0f0f853d 100644 --- a/src/views/admin/partials/menu.tpl +++ b/src/views/admin/partials/menu.tpl @@ -20,6 +20,7 @@
  • Registration Queue
  • Groups
  • Flags
  • +
  • IP Blacklist
  • @@ -173,6 +174,7 @@
  • Registration Queue
  • Groups
  • Flags
  • +
  • IP Blacklist