代码之家  ›  专栏  ›  技术社区  ›  meder omuraliev

如何在我的IRC机器人上实现反垃圾邮件技术?

  •  2
  • meder omuraliev  · 技术社区  · 15 年前

    我在一个有数百名用户的公共频道上运行我的机器人。昨天,一个人进来滥用它。

    我想让任何人使用机器人,但如果他们连续发送垃圾邮件命令,如果他们不是我调试时的机器人“所有者”,那么我想将他们添加到一个忽略列表中,该列表将在一小时左右到期。

    我认为的一种方法是将所有用户的所有命令保存在字典中,例如:

    ({
      'meder@freenode': [{command:'.weather 20851', timestamp: 209323023 }],
      'jack@efnet': [{command:'.seen john' }]
    })
    

    我会设置一个cron作业,每24小时刷新一次,但我基本上会确定一个人是否在15秒内发出了X个命令,并将它们添加到忽略列表中。

    lastCommands = [], limit = 5;
    
    function handleCommand( timeObj, action ) {
        if ( lastCommands.length < limit ) {
            action();
        } else {
            // enumerate through lastCommands and compare the timestamps of all 5 commands
            // if the user is the same for all 5 commands, and...
            // if the timestamps are all within the vicinity of 20 seconds
            // add the user to the ignoreList
        }  
    }
    
    
    watch_for('command', function() {
       handleCommand({timestamp: 2093293032, user: user}, function(){ message.say('hello there!') })
    });
    

    如果您能就此事提出任何建议,我将不胜感激。

    4 回复  |  直到 15 年前
        1
  •  11
  •   nmichaels    15 年前

    下面是一个简单的算法:

    • 每次用户向bot发送命令时,增加一个与该用户相关的数字。如果这是新用户,请为他们创建数字并将其设置为1。
    • 当用户的数字增加到某个值(比如15)时,将其设置为100。
    • 每个<期间>秒,运行列表并将所有数字减1。零表示可以释放用户的号码。

    在执行命令之前和增加用户计数器之后,检查它是否超过magic max值(上面的15)。如果是,请在执行命令之前退出。

    这可以让你在一段时间后对限制行为进行评分并原谅过度行为。将所需的ban长度除以递减周期,以查找当用户超过阈值(100以上)时要设置的数字。如果某个特定用户在被禁止后继续发送命令,您还可以将其添加到数字中。

        2
  •  3
  •   Ivo Wetzel    15 年前

    纳森已经提供了一个解决方案,但是可以减少所需的代码。

    var user = {};
    user.lastCommandTime = new Date().getTime(); // time the user send his last command
    user.commandCount = 0; // command limit counter
    user.maxCommandsPerSecond = 1; // commands allowed per second
    
    function handleCommand(obj, action) {
        var user = obj.user, now = new Date().getTime();
    
        var timeDifference = now - user.lastCommandTime;
        user.commandCount = Math.max(user.commandCount - (timeDifference / 1000 * user.maxCommandsPerSecond), 0) + 1;
        user.lastCommandTime = now; 
    
        if (user.commandCount <= user.maxCommandsPerSecond) {
            console.log('command!');
    
        } else {
            console.log('flooding');
        }
    }
    
    
    var obj = {user: user};
    var e = 0;
    function foo() {
        handleCommand(obj, 'foo');
        e += 250;
        setTimeout(foo, 400 + e);
    }
    foo();
    

    在这个实现中,不需要每隔X秒进行一次列表或一些全局回调,我们只需要减少 commandCount 每次有新消息时,基于与上一个命令的时间差,也可以允许特定用户使用不同的命令速率。

    我们只需要用户对象上的3个新属性:)

        3
  •  3
  •   Alfred    15 年前

    雷迪斯

    我会使用速度极快的高级键值存储 redis 写这样的东西,因为:

    • 它快得惊人。
    • 不需要cronjob,因为您可以设置 expire 在钥匙上。
    • 它有原子操作来 increment
    • 您可以使用redis cli进行原型设计。

    我自己真的很喜欢 node_redis 作为redis客户端。它是一个非常快速的redis客户端,可以使用npm轻松安装。

    算法

    我想我的算法应该是这样的:

    1. 为每个用户创建一个唯一的键,该键对连续执行的命令进行计数。还将expire设置为不再将用户标记为垃圾邮件发送者的时间。让我们假设垃圾邮件发送者有一个昵称 x expire 15 .

      redis cli内部
      增量x
      到期日x 15

      get x 15秒后,钥匙不再存在。

    2. 若密钥的值大于阈值,则将用户标记为垃圾邮件发送者。

      得到x

        4
  •  -1
  •   Robin Duckett    15 年前

    这些答案似乎走错了方向。

    IRC服务器将断开您的客户端的连接,无论您是否正在“调试”,如果客户端或bot正在淹没通道或服务器。

    @nmichaels 已详细说明,但取决于bot与服务器本身的网络连接。

    推荐文章