Browse Source

add cooldown to channel invites (fixes #66)

Byron Jones 6 years ago
parent
commit
bc2e18e490
3 changed files with 47 additions and 9 deletions
  1. 1 0
      lib/LogBot/Config.pm
  2. 20 0
      lib/LogBot/MemCache.pm
  3. 26 9
      logbot-irc

+ 1 - 0
lib/LogBot/Config.pm

@@ -95,6 +95,7 @@ sub load_config {
     $config->{timing}->{ping_timeout_attempts}   ||= 5;
     $config->{timing}->{channel_reload_interval} ||= 60 * 60;
     $config->{timing}->{topic_reload_interval}   ||= 24 * 60 * 60;
+    $config->{timing}->{invite_cooldown}         ||= 3 * 60;
 
     make_path($config->{_derived}->{root});
     make_path(path_for($config, 'queue'));

+ 20 - 0
lib/LogBot/MemCache.pm

@@ -46,6 +46,19 @@ sub cached {
     return $value;
 }
 
+sub get {
+    my ($self, $key) = @_;
+    my $cache = $self->{cache};
+    my $cached = memcached_get($cache, $key);
+    return defined $cached ? decode('UTF-8', $cached) : undef;
+}
+
+sub set {
+    my ($self, $key, $value) = @_;
+    my $cache = $self->{cache};
+    memcached_set($cache, $key, encode('UTF-8', $value));
+}
+
 1;
 
 package LogBot::MemCache::None;
@@ -64,4 +77,11 @@ sub cached {
     return $callback->();
 }
 
+sub get {
+    return undef;
+}
+
+sub set {
+}
+
 1;

+ 26 - 9
logbot-irc

@@ -22,6 +22,7 @@ use List::MoreUtils qw( natatime );
 use List::Util qw( any min );
 use LogBot::Config qw( find_config load_config reload_config save_config );
 use LogBot::JobQueue;
+use LogBot::MemCache ();
 use LogBot::Util qw( file_for logbot_init normalise_channel slurp source_to_nick squash_error timestamp touch );
 use Mojo::Log ();
 use Readonly;
@@ -29,7 +30,7 @@ use Time::HiRes ();
 use Try::Tiny qw( catch try );
 
 # globals
-my ($config, $state, $connection, $job_queue, $log);
+my ($config, $state, $connection, $job_queue, $log, $memcache);
 
 #
 
@@ -124,7 +125,6 @@ sub irc_connect {
 sub block_invite {
     my ($source, $channel) = @_;
     my $who = source_to_nick($source);
-    $config = reload_config($config);
 
     foreach my $blocked (@{ $config->{blocked} }) {
         if (substr($blocked, 0, 1) eq '#') {
@@ -229,6 +229,7 @@ $pid && die 'logbot-irc (' . $config->{name} . ") is already running\n";
 logbot_init($config);
 init_logging();
 $job_queue = LogBot::JobQueue->new($config);
+$memcache = LogBot::MemCache->new(binary => !$config->{_derived}->{is_dev});
 
 # init signals and state
 $SIG{HUP} = sub {
@@ -362,15 +363,17 @@ while (1) {
     # invited
     if ($message =~ /^:(\S+) INVITE \S+ :(#.+)/) {
         my ($source, $channel) = ($1, normalise_channel($2));
+        my $who = source_to_nick($source);
+        $config = reload_config($config);
 
+        # honour invite blocklist
         if (block_invite($source, $channel)) {
             say timestamp(), ' -- ignoring invite to blocked ', $channel, ' from ', $source;
             $log->info('ignoring invite to blocked ' . $channel . ' from ' . $source);
             next;
         }
 
-        my $who = source_to_nick($source);
-
+        # ignore no-op invites
         if ($state->{channels_in}->{$channel}) {
             say timestamp(), ' -- ignoring invite to already-in ', $channel, ' from ', $who;
             $log->info('ignoring invite to already-in ' . $channel . ' from ' . $who);
@@ -384,10 +387,23 @@ while (1) {
             next;
         }
 
+        # cooldown
+        my $cooldown_key = $config->{name} . $channel . ',' . $source;
+        if (my $last_request = $memcache->get($cooldown_key)) {
+            if ($time - $last_request < $config->{timing}->{invite_cooldown}) {
+                irc_send_message($who, "unable to join $channel: please wait longer before asking again");
+                $log->info("rejecting invite to $channel from $who: cooldown expires in "
+                        . ($config->{timing}->{invite_cooldown} - ($time - $last_request))
+                        . 's');
+                next;
+            }
+        }
+
         $state->{pending_invites}->{$channel} = {
-            who    => lc($who),
-            source => $source,
-            ops    => [],
+            who          => lc($who),
+            source       => $source,
+            ops          => [],
+            cooldown_key => $cooldown_key,
         };
         irc_send('JOIN ' . $channel);
         next;
@@ -463,11 +479,12 @@ while (1) {
             publish(0, $config->{irc}->{nick}, $channel, $announcement);
 
         } else {
-            say timestamp(), ' -- join ', $channel, ' rejected - non-op invite from ', $who;
-            $log->info('join ' . $channel . ' rejected - non-op invite from ' . $who);
+            say timestamp(), ' -- join ', $channel, ' rejected - non-op invite from ', $invite->{source};
+            $log->info('join ' . $channel . ' rejected - non-op invite from ' . $invite->{source});
 
             irc_send('PART ' . $channel);
             irc_send_message($invite->{who}, 'unable to join ' . $channel . ': you are not a channel op');
+            $memcache->set($invite->{cooldown_key} => $time);
 
         }
         next;