From c6d38c7575a09c2b8344857e01a728298148628b Mon Sep 17 00:00:00 2001 From: William Heimbigner Date: Sun, 29 Jan 2012 07:50:57 +0000 Subject: State tracking of user accounts, use freenode's CAP features to avoid whois'ing users and improve access control for bot's commands, remove some dead code --- config-default/commands.xml | 45 +++++++++------------- config-default/users.xml | 59 ++++++++++++++-------------- meta.pl | 18 +++++---- modules/command.pl | 19 +++------ modules/event.pl | 93 ++++++++++++++++++++++++++++++++++----------- modules/xml.pl | 23 +++-------- 6 files changed, 137 insertions(+), 120 deletions(-) diff --git a/config-default/commands.xml b/config-default/commands.xml index 098c104..7b8ecab 100644 --- a/config-default/commands.xml +++ b/config-default/commands.xml @@ -46,17 +46,25 @@ $conn->privmsg($event->{to}->[0], "$result results found."); ]]> - + {person}->{$nick} = { 'host' => $host }; + my $acct = lc $1; + my $flags = $2; + if ($flags =~ /d/) { + $conn->privmsg($event->{to}->[0], "The d flag may not be assigned over IRC. Edit the configuration manually."); + return; + } + $::users->{person}->{$acct} = { 'flags' => $flags }; ASM::XML->writeUsers(); - $conn->privmsg($event->{to}->[0], "Hiya $nick"); + $conn->privmsg($event->{to}->[0], "Flags for NickServ account $acct set to $flags"); + ]]> + + + privmsg($event->{to}->[0], "This command has been deprecated"); ]]> - + {person}->{$nick}->{flags})) { @@ -66,7 +74,7 @@ } ]]> - + privmsg($event->{to}->[0], "Flags for $nick set to $flags"); ]]> - + {person}->{$nick}); @@ -87,25 +95,6 @@ $conn->privmsg($event->{to}->[0], "Byebye $nick"); ]]> - - - {channel}->{$chan}->{op}; - if ($set eq "no") { $set = "when"; } else { $set = "no"; } - $::channels->{channel}->{$chan}->{op} = $set; - $conn->privmsg($event->{to}->[0], "Operator action for $chan set to \"$set\"."); - ]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/meta.pl b/meta.pl index 94e9aef..c9d5446 100755 --- a/meta.pl +++ b/meta.pl @@ -17,7 +17,9 @@ use Getopt::Long; %::eline=(); $::pass = ''; @::string_blacklist=(); -@::joinrate=(); #I really need to stop doing this shit +$::netsplit = 0; +$::debug = 0; +$::cset = ''; BEGIN { my @modules = qw/Util Xml Inspect Event Services Log Command Classes Mysql/; @@ -26,21 +28,23 @@ require 'modules/' . lc $_ . '.pl' foreach @modules; sub init { my ( $conn, $host ); - my $debug = 0; my $irc = new Net::IRC; - $::cset = ''; - GetOptions( 'debug|d!' => \$debug, + GetOptions( 'debug|d!' => \$::debug, 'pass|p:s' => \$::pass, 'config|c:s' => \$::cset ); - $::debug = $debug; + if ($::cset eq '') { + $::cset = 'config-default'; + } else { + $::cset = "config-$::cset"; + } ASM::XML->readXML(); mkdir($::settings->{log}->{dir}); $::log = ASM::Log->new($::settings->{log}); $::pass = $::settings->{pass} if $::pass eq ''; $host = ${$::settings->{server}}[rand @{$::settings->{server}}]; print "Connecting to $host\n"; - $irc->debug($debug); + $irc->debug($::debug); $::db = ASM::DB->new($::mysql->{db}, $::mysql->{host}, $::mysql->{port}, $::mysql->{user}, $::mysql->{pass}, $::mysql->{table}, $::mysql->{dblog}); $conn = $irc->newconn( Server => $host, Port => $::settings->{port} || '6667', @@ -49,7 +53,7 @@ sub init { Username => $::settings->{username}, Password => $::settings->{pass}, Pacing => 1 ); - $conn->debug($debug); + $conn->debug($::debug); $::inspector = ASM::Inspect->new(); $::services = ASM::Services->new(); $::commander = ASM::Commander->new(); diff --git a/modules/command.pl b/modules/command.pl index 889a3de..ded53a5 100644 --- a/modules/command.pl +++ b/modules/command.pl @@ -20,26 +20,17 @@ sub command my $cmd = $args; my $d1; my $nick = lc $event->{nick}; + my $acct = lc $::sn{$nick}->{account}; # return 0 unless (ASM::Util->speak($event->{to}->[0])); foreach my $command ( @{$::commands->{command}} ) { unless (ASM::Util->speak($event->{to}->[0])) { next unless (defined($command->{nohush}) && ($command->{nohush} eq "nohush")); } - if (defined($command->{flag})) { - next unless defined($::users->{person}->{$nick}); - next unless defined($::users->{person}->{$nick}->{flags}); - next unless (grep {$_ eq $command->{flag}} split('', $::users->{person}->{$nick}->{flags})); - if ($::users->{person}->{$nick}->{host} ne 'IDENTIFY') { - next unless (lc $::users->{person}->{$nick}->{host} eq lc $event->{host}); - } - else { - if ( $cmd =~ /$command->{cmd}/ ){ - push (@{$::idqueue{$nick}}, [$cmd, $command, $event]); - $conn->sl("whois $nick $nick"); - last; - } - } + if (defined($command->{flag})) { #If the command is restricted, + next unless defined($::users->{person}->{$acct}); #make sure the requester has an account + next unless defined($::users->{person}->{$acct}->{flags}); #make sure the requester has flags defined + next unless (grep {$_ eq $command->{flag}} split('', $::users->{person}->{$acct}->{flags})); #make sure the requester has the needed flags } if ($cmd=~/$command->{cmd}/) { print strftime("%F %T ", gmtime) . "$event->{from} told me: $cmd \n"; diff --git a/modules/event.pl b/modules/event.pl index a8a9d99..a659461 100644 --- a/modules/event.pl +++ b/modules/event.pl @@ -59,13 +59,22 @@ sub new $conn->add_handler('318', \&whois_end); $conn->add_handler('311', \&whois_user); $conn->add_handler('352', \&on_whoreply); + $conn->add_handler('354', \&on_whoxreply); + $conn->add_handler('account', \&on_account); bless($self); return $self; } - + +sub on_account +{ + my ($conn, $event) = @_; + $::sn{lc $event->{nick}}{account} = lc $event->{args}->[0]; +} + sub on_connect { my ($conn, $event) = @_; # need to check for no services $conn->privmsg( 'NickServ', "ghost $::settings->{nick} $::settings->{pass}" ) if lc $event->{args}->[0] ne lc $::settings->{nick}; + $conn->sl('CAP REQ :extended-join multi-prefix account-notify'); #god help you if you try to use this bot off freenode } sub on_join { @@ -75,20 +84,12 @@ sub on_join { my $nick = lc $event->{nick}; my $chan = lc $event->{to}->[0]; my $rate; - push( @::joinrate, time ); - while ( time >= $::joinrate[0] + 1 ) { - last if ( $#{ @::joinrate } == 0 ); - shift( @::joinrate ); - } - $rate = $#{ @::joinrate}+1; - print "on_join rate = $rate\n" if $::debug; - if ( $rate == 20 ) { - $conn->privmsg('##asb-nexus', "AfterDeath: I think I'm seeing a netjoin!"); - } + print Dumper($event) if $::debug; if ( lc $conn->{_nick} eq lc $nick) { $::sc{$chan} = {}; mkdir($::settings->{log}->{dir} . $chan); - $conn->sl("who $chan"); +# $conn->sl("who $chan"); + $conn->sl('who ' . $chan . ' %tcfnuhra,314'); # I don't know what the hell this was for but I'm disabling it for now # #TODO: make it settable via config. Hardcoded channames ftl. # if ($chan eq '##linux') { @@ -107,20 +108,31 @@ sub on_join { } @mship = (@mship, $chan); $::sn{$nick}->{mship} = \@mship; - $::inspector->inspect( $conn, $event ); - $::db->logg($event); } else { $::sn{$nick} = {}; $::sn{$nick}->{mship} = [ $chan ]; $::sn{$nick}->{dnsbl} = 0; - if (defined($::needgeco{$nick})) { - $::needgeco{$nick} = [ @{$::needgeco{$nick}}, $evcopy ]; - $::db->logg($event); - } else { - $::needgeco{$nick} = [ $evcopy ]; - $conn->sl("whois $nick"); - } + $::sn{$nick}->{netsplit} = 0; + $::sn{$nick}->{gecos} = $event->{args}->[1]; + $::sn{$nick}->{user} = $event->{user}; + $::sn{$nick}->{host} = $event->{host}; + $::sn{$nick}->{account} = lc $event->{args}->[0]; +# if (defined( $::needgeco{$lnick} )) { +# foreach my $event (@{$::needgeco{$lnick}}) { +# $::inspector->inspect($conn, $event); +# $::db->logg( $event ); +# } +# delete $::needgeco{$lnick}; +# if (defined($::needgeco{$nick})) { +# $::needgeco{$nick} = [ @{$::needgeco{$nick}}, $evcopy ]; +# $::db->logg($event); +# } else { +# $::needgeco{$nick} = [ $evcopy ]; +# $conn->sl("whois $nick"); +# } } + $::inspector->inspect( $conn, $event ) unless $::netsplit; + $::db->logg($event); $::log->logg( $event ); } @@ -193,14 +205,20 @@ sub on_quit } $event->{to} = \@channels; $::db->logg( $event ); - delete($::sn{lc $event->{nick}}); - $::inspector->inspect( $conn, $event ); + if (($::netsplit == 0) && ($event->{args}->[0] eq "*.net *.split")) { #special, netsplit situation + $conn->privmsg("##asb-nexus", "Entering netsplit mode - JOIN and QUIT inspection will be disabled for 60 minutes"); + $::netsplit = 1; + $conn->schedule(60*60, sub { $::netsplit = 0; }); + } + $::inspector->inspect( $conn, $event ) unless $::netsplit; $::log->logg( $event ); + delete($::sn{lc $event->{nick}}); } sub blah { my ($self, $event) = @_; + print Dumper($event) if $::debug; $::inspector->inspect($self, $event); } @@ -403,12 +421,41 @@ sub whois_user { } } +sub on_whoxreply +{ + my ($conn, $event) = @_; + return unless $event->{args}->[1] eq '314'; + my ($tgt, $magic, $chan, $user, $host, $nick, $flags, $account, $gecos) = @{$event->{args}}; + my ($voice, $op) = (0, 0); + print Dumper($event) if $::debug; + $op = 1 if ( $flags =~ /\@/ ); + $voice = 1 if ($flags =~ /\+/); + $nick = lc $nick; $chan = lc $chan; + $::sn{$nick} = {} unless defined $::sn{lc $nick}; + my @mship=(); + if (defined($::sn{$nick}->{mship})) { + @mship = @{$::sn{$nick}->{mship}}; + } + @mship = grep { lc $_ ne $chan } @mship; + @mship = (@mship, $chan); + $::sn{$nick}->{mship} = \@mship; + $::sn{$nick}->{gecos} = $gecos; + $::sn{$nick}->{user} = $user; + $::sn{$nick}->{host} = $host; + $::sn{$nick}->{account} = lc $account; + $::sc{$chan}{users}{$nick} = {}; + $::sc{$chan}{users}{$nick}{op} = $op; + $::sc{$chan}{users}{$nick}{voice} = $voice; + +} + sub on_whoreply { my ($conn, $event) = @_; my ($tgt, $chan, $user, $host, $server, $nick, $flags, $hops_and_gecos) = @{$event->{args}}; my ($voice, $op) = (0, 0); my ($hops, $gecos); + print Dumper($event) if $::debug; $op = 1 if ( $flags =~ /\@/ ); $voice = 1 if ($flags =~ /\+/); if ($hops_and_gecos =~ /^(\d+) (.*)$/) { diff --git a/modules/xml.pl b/modules/xml.pl index ce7712d..30b5f30 100644 --- a/modules/xml.pl +++ b/modules/xml.pl @@ -8,9 +8,7 @@ use IO::All; $::xs1 = XML::Simple->new( KeyAttr => ['id'], Cache => [ qw/storable memcopy/ ]); sub readXML { - my ( $p ) = $::cset; #@_; - $p = 'default' if $p eq ''; - $p = "config-$p"; + my ( $p ) = $::cset; my @fchan = ( 'event', keys %::RISKS ); $::settings = $::xs1->XMLin( "$p/settings.xml", ForceArray => ['host'], 'GroupTags' => { altnicks => 'altnick', server => 'host', autojoins => 'autojoin' }); $::channels = $::xs1->XMLin( "$p/channels.xml", ForceArray => \@fchan ); @@ -21,9 +19,7 @@ sub readXML { } sub writeXML { - my ( $p ) = $::cset; #@_; - $p = 'default' if $p eq ''; - $p = "config-$p"; + my ( $p ) = $::cset; $::xs1->XMLout($::settings, RootName => 'settings', KeyAttr => ['id'], GroupTags => { altnicks => 'altnick', server => 'host', autojoins => 'autojoin' }, ValueAttr => { debug => 'content', nick => 'content', port => 'content', @@ -35,24 +31,15 @@ sub writeXML { } sub writeChannels { - my ( $p ) = $::cset; #@_; - $p = 'default' if $p eq ''; - $p = "config-$p"; - $::xs1->XMLout($::channels, RootName => 'channels', KeyAttr => ['id']) > io("$p/channels.xml"); + $::xs1->XMLout($::channels, RootName => 'channels', KeyAttr => ['id']) > io("$::cset/channels.xml"); } sub writeUsers { - my ( $p ) = $::cset; #@_; - $p = 'default' if $p eq ''; - $p = "config-$p"; - $::xs1->XMLout($::users, RootName => 'people', KeyAttr => ['id']) > io("$p/users.xml"); + $::xs1->XMLout($::users, RootName => 'people', KeyAttr => ['id']) > io("$::cset/users.xml"); } sub writeSettings { - my ( $p ) = $::cset; #@_; - $p = 'default' if $p eq ''; - $p = "config-$p"; - $::xs1->XMLout($::settings, RootName => 'settings', GroupTags => { altnicks => 'altnick', server => 'host', autojoins => 'autojoin' }, NoAttr => 1) > io("$p/settings.xml"); + $::xs1->XMLout($::settings, RootName => 'settings', GroupTags => { altnicks => 'altnick', server => 'host', autojoins => 'autojoin' }, NoAttr => 1) > io("$::cset/settings.xml"); } return 1; -- cgit v1.2.3