]> git.example.dev Git - binbsis50.git/commitdiff
added ability for privileged users to ban players
authorLuigi Pinca <luigipinca@gmail.com>
Fri, 30 May 2014 19:29:27 +0000 (21:29 +0200)
committerLuigi Pinca <luigipinca@gmail.com>
Fri, 30 May 2014 19:29:27 +0000 (21:29 +0200)
app.js
lib/middleware/ban-handler.js [new file with mode: 0644]
lib/middleware/error-handler.js [moved from lib/middleware/errorHandler.js with 100% similarity]
lib/rooms.js
lib/sparks.js
lib/utils.js
package.json
public/js/app.js
views/banned.jade [new file with mode: 0644]

diff --git a/app.js b/app.js
index bdeb7d35bee9d7c91d06727d859efaf3162947bd..9657b035d54ade681a28348396f84a8988515f57 100644 (file)
--- a/app.js
+++ b/app.js
@@ -2,7 +2,8 @@
  * Module dependencies.
  */
 
-var errorHandler = require('./lib/middleware/errorHandler')
+var banHandler = require('./lib/middleware/ban-handler')
+  , errorHandler = require('./lib/middleware/error-handler')
   , express = require('express')
   , favicon = require('serve-favicon')
   , http = require('http')
@@ -29,6 +30,7 @@ var app = express()
 app.set('view engine', 'jade');
 app.use('/static', express.static(pub, {maxAge: 2419200000})); // 4 weeks = 2419200000 ms
 app.use(favicon(pub + '/img/favicon.ico', {maxAge: 2419200000}));
+app.use(banHandler);
 app.use(urlencoded());
 app.use(cookieParser);
 app.use(session({
diff --git a/lib/middleware/ban-handler.js b/lib/middleware/ban-handler.js
new file mode 100644 (file)
index 0000000..7f608a4
--- /dev/null
@@ -0,0 +1,30 @@
+/**
+ * Module dependencies.
+ */
+
+var db = require('../redis-clients').users
+  , forwarded = require('forwarded-for')
+  , utils = require('../utils');
+
+/**
+ * Expose a middleware to filter banned IPs.
+ */
+
+module.exports = function(req, res, next) {
+  var address = forwarded(req, req.headers);
+
+  db.ttl(['ban:' + address.ip], function(err, ttl) {
+    if (err) {
+      return next(err);
+    }
+
+    if (ttl < 0) {
+      return next();
+    }
+
+    res.render('banned', {
+      slogan: utils.randomSlogan(),
+      ttl: Math.round(ttl / 60)
+    });
+  });
+};
index fcde1f75c2939ea53589e7f0540d1cbead59f92b..846900fca9d5a02f85c49c2367c0288b505bb0b6 100644 (file)
@@ -308,7 +308,7 @@ Room.prototype.onGuess = function(spark, guess) {
  */
 
 Room.prototype.onIgnore = function(who, executor, callback) {
-  // Check if the player to be ignored is in the room
+  // Check if the player is in the room
   if (this.usersData[who]) {
     sparks[who].send('chatmsg', executor + ' is ignoring you.', 'binb', who);
     return callback(true, who);
@@ -317,32 +317,47 @@ Room.prototype.onIgnore = function(who, executor, callback) {
 };
 
 /**
- * Kick a player.
+ * Kick and optionally ban a player.
  */
 
-Room.prototype.onKick = function(who, why, executor, callback) {
+Room.prototype.onKick = function(who, why, executor, duration, callback) {
   var room = this;
 
+  if (typeof duration === 'function') {
+    callback = duration;
+    duration = 0;
+  }
+
   usersdb.hget(['user:' + executor, 'role'], function(err, role) {
     if (err) {
       console.error(err.message);
       return callback(true);
     }
 
-    // Check role
-    if (role > 0) {
-      if (room.usersData[who]) {
-        if (why) {
-          why = ' (' + why + ')';
-        }
-        var notice = 'you have been kicked by ' + executor + why + '.'
-          , recipient = sparks[who];
-        recipient.send('chatmsg', notice, 'binb', who);
-        recipient.end();
+    // Check if the sender can kick other players
+    if ((role || 0) < 1) {
+      return callback(false);
+    }
+
+    // Check if the target player is in the room
+    if (room.usersData[who]) {
+      var notice = 'you have been kicked by ' + executor +
+        (why && ' (' + why + ')') + '.';
+      var target = sparks[who];
+
+      if (duration) {
+        usersdb.setex(['ban:' + target.address.ip, duration, who], function(err) {
+          if (err) {
+            console.error(err.message);
+          }
+        });
       }
-      return callback(true);
+
+      target.send('chatmsg', notice, 'binb', who);
+      target.end();
     }
-    callback(false);
+
+    callback(true);
   });
 };
 
index a3423542ac318c15b466b5fa51d57c0068559f67..a78229d66a4aeb46a0016156a865a8beb948105d 100644 (file)
@@ -3,6 +3,8 @@
  */
 
 var config = require('../config')
+  , db = require('../lib/redis-clients').users
+  , forwarded = require('forwarded-for')
   , fs = require('fs')
   , minify = require('uglify-js').minify
   , Primus = require('primus')
@@ -13,6 +15,7 @@ var config = require('../config')
   , sessionstore
   , sparks = Object.create(null) // Sparks of all rooms
   , utils = require('./utils')
+  , banDuration = utils.banDuration
   , isFunction = utils.isFunction
   , isString = utils.isString;
 
@@ -85,8 +88,18 @@ var authorize = function(req, authorized) {
       console.error(err.message);
       return authorized(err);
     }
-    req.user = session.user;
-    authorized();
+    var address = forwarded(req, req.headers);
+    db.exists(['ban:' + address.ip], function(err, exists) {
+      if (err) {
+        console.error(err.message);
+        return authorized(err);
+      }
+      if (exists) {
+        return authorized(new Error('banned IP address'));
+      }
+      req.user = session.user;
+      authorized();
+    });
   });
 };
 
@@ -135,6 +148,16 @@ var connection = function(spark) {
 
 var joinRoom = function(room, spark) {
   room = rooms[room];
+  spark.on('ban', function(who, why, duration, callback) {
+    if (
+      isString(who) &&
+      isString(why) &&
+      isString(duration) &&
+      isFunction(callback)
+    ) {
+      room.onKick(who, why, spark.nickname, banDuration(duration), callback);
+    }
+  });
   spark.on('chatmsg', function(msg, to) {
     if (isString(msg)) {
       room.onChatMessage(msg, spark, to);
index a180ca168878910424d6a348dc4cbd3cfbeb7039..40eaefb91256ccd208282f99c75b76f41718d182 100644 (file)
@@ -1,3 +1,12 @@
+/**
+ * Convert the duration of a ban from minutes to seconds and return the value.
+ * Default duration is 15 minutes.
+ */
+
+exports.banDuration = function(str) {
+  return /^[1-9][0-9]*$/.test(str) ? str * 60 : 900;
+};
+
 /**
  * Helper function used to build leaderboards.
  * Rearrange database results in an object.
index d6e35d2ae62450bddbfef1abef65fd60e2a4695b..0cab662dab1ec8924e8334618a716648dff1ae23 100644 (file)
@@ -8,6 +8,7 @@
     "cookie-parser": "1.1.x",
     "express": "4.3.x",
     "express-session": "1.2.x",
+    "forwarded-for": "0.0.x",
     "jade": "1.3.x",
     "nodemailer": "0.6.x",
     "primus": "2.2.x",
index 32f6e1b2dad4b6e8c2ef1ec036e295fc5bdcc72b..298818b4c740197bfaee64caa8b17d77432c0b44 100644 (file)
     });
   };
 
-  // Kick a player
-  var kickPlayer = function(args, outcome) {
-    outcome.append('you are not allowed to kick a player.');
-    if (!subscriber) {
-      return addChatEntry(outcome);
-    }
-    var why = args[1] || '';
-    primus.send('kick', args[0], why, function(success) {
-      if (!success) {
-        addChatEntry(outcome);
-      }
-    });
-  };
-
   var loadTrack = function(previewUrl) {
     jplayer.jPlayer('mute');
     jplayer.jPlayer('setMedia', {m4a: previewUrl});
     addFeedback('What is this song?');
   };
 
+  // Return a function that will kick or ban a player
+  var punishPlayer = function(punishment) {
+    return function(tokens, outcome) {
+      outcome.append('you are not allowed to ' + punishment + ' a player.');
+      if (!subscriber) {
+        return addChatEntry(outcome);
+      }
+
+      var args = [punishment, tokens[0]];
+
+      if (punishment === 'kick') {
+        args.push(tokens[1] || '');
+      }
+      else if (!tokens[1]) {
+        args.push('', '');
+      }
+      else if (!tokens[2]) {
+        if (/^[1-9][0-9]*$/.test(tokens[1])) {
+          args.push('', tokens[1]);
+        }
+        else {
+          args.push(tokens[1], '');
+        }
+      }
+      else {
+        args.push(tokens[1], tokens[2]);
+      }
+
+      args.push(function(success) {
+        if (!success) {
+          addChatEntry(outcome);
+        }
+      });
+
+      primus.send.apply(primus, args);
+    };
+  };
+
   // Return a function that will add a random text from the given set, with the given style
   var randomFeedback = function(set, style) {
     var card = set.length;
   };
 
   var slashcommands = {
+    ban: {
+      checkrecipient: true,
+      fn: punishPlayer('ban'),
+      minargs: 1,
+      usage: 'usage: /ban &lt;player name&gt; [message] [duration]'
+    },
     clear: {
       fn: function() {
         DOM.chat.empty();
     },
     kick: {
       checkrecipient: true,
-      fn: kickPlayer,
+      fn: punishPlayer('kick'),
       minargs: 1,
       usage: 'usage: /kick &lt;player name&gt; [message]'
     },
       volume: 1
     });
     primus.on('alreadyinaroom', alreadyInARoom);
+    primus.on('close', disconnect);
     primus.on('invalidnickname', invalidNickName);
     primus.on('ready', ready);
     primus.on('updateoverview', updateRoomsOverview);
     primus.send('getoverview', roomsOverview);
   });
-  primus.on('close', disconnect);
 
 })();
diff --git a/views/banned.jade b/views/banned.jade
new file mode 100644 (file)
index 0000000..6adde56
--- /dev/null
@@ -0,0 +1,16 @@
+extends layout
+
+block title
+  title binb :: banned
+
+block sections
+  section
+    .row
+      .span12.offset2
+        .alert.alert-error.alert-block
+          h4.alert-heading Error!
+          | Yuo have been banned.
+          br
+          | Your ban will expire in #{ttl} minutes.
+
+block scripts